Coverage Report

Created: 2026-05-30 08:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_si.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_psi_eit.c : TS demuxer SI handling
3
 *****************************************************************************
4
 * Copyright (C) 2014-2016 - VideoLAN Authors
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 *****************************************************************************/
19
#ifdef HAVE_CONFIG_H
20
# include "config.h"
21
#endif
22
23
#include <vlc_common.h>
24
#include <vlc_demux.h>
25
#include <vlc_meta.h>
26
#include <vlc_epg.h>
27
#include <vlc_charset.h>   /* FromCharset, for EIT */
28
#include <vlc_input.h>
29
30
#ifndef _DVBPSI_DVBPSI_H_
31
 #include <dvbpsi/dvbpsi.h>
32
#endif
33
#include <dvbpsi/demux.h>
34
#include <dvbpsi/descriptor.h>
35
#include <dvbpsi/sdt.h>
36
#include <dvbpsi/eit.h> /* EIT support */
37
#include <dvbpsi/tot.h> /* TDT support */
38
#include <dvbpsi/dr.h>
39
#include <dvbpsi/psi.h>
40
#include "../../mux/mpeg/dvbpsi_compat.h" /* dvbpsi_messages */
41
42
#include "ts_si.h"
43
#include "ts_arib.h"
44
#include "ts_decoders.h"
45
46
#include "ts_pid.h"
47
#include "ts_streams_private.h"
48
#include "ts.h"
49
#include "../dvb-text.h"
50
51
#ifdef HAVE_ARIBB24
52
 #include <aribb24/decoder.h>
53
#endif
54
55
#include <time.h>
56
#include <assert.h>
57
#include <limits.h>
58
59
struct ts_si_context_t
60
{
61
    dvbpsi_t *p_handle;
62
    int       i_version;
63
};
64
65
#ifndef SI_DEBUG_EIT
66
 #define SI_DEBUG_TIMESHIFT(t)
67
#else
68
 static time_t i_eit_debug_offset = 0;
69
 #define SI_DEBUG_TIMESHIFT(t) \
70
    do {\
71
        if( i_eit_debug_offset == 0 )\
72
            i_eit_debug_offset = time(NULL) - t;\
73
        t = t + i_eit_debug_offset;\
74
    } while(0);
75
#endif
76
77
78
static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
79
                                uint16_t i_extension, void *p_pid_cbdata );
80
81
void ts_si_Packet_Push( ts_pid_t *p_pid, const uint8_t *p_pktbuffer )
82
17.2k
{
83
17.2k
    if( likely(p_pid->type == TYPE_SI) &&
84
17.2k
        dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) )
85
17.2k
        dvbpsi_packet_push( p_pid->u.p_si->p_ctx->p_handle, (uint8_t *) p_pktbuffer );
86
17.2k
}
87
88
static char *EITConvertToUTF8( demux_t *p_demux,
89
                               const unsigned char *psz_instring,
90
                               size_t i_length,
91
                               bool b_broken )
92
1.33k
{
93
1.33k
    demux_sys_t *p_sys = p_demux->p_sys;
94
#ifdef HAVE_ARIBB24
95
    if( p_sys->standard == TS_STANDARD_ARIB )
96
    {
97
        if ( !p_sys->arib.p_instance )
98
            p_sys->arib.p_instance = arib_instance_new( p_demux );
99
        if ( !p_sys->arib.p_instance )
100
            return NULL;
101
        arib_decoder_t *p_decoder = arib_get_decoder( p_sys->arib.p_instance );
102
        if ( !p_decoder )
103
            return NULL;
104
105
        char *psz_outstring = NULL;
106
        size_t i_out;
107
108
        i_out = i_length * 4;
109
        psz_outstring = (char*) calloc( i_out + 1, sizeof(char) );
110
        if( !psz_outstring )
111
            return NULL;
112
113
        arib_initialize_decoder( p_decoder );
114
        i_out = arib_decode_buffer( p_decoder, psz_instring, i_length,
115
                                    psz_outstring, i_out );
116
        arib_finalize_decoder( p_decoder );
117
118
        return psz_outstring;
119
    }
120
#else
121
1.33k
    VLC_UNUSED(p_sys);
122
1.33k
#endif
123
    /* Deal with no longer broken providers (no switch byte
124
      but sending ISO_8859-1 instead of ISO_6937) without
125
      removing them from the broken providers table
126
      (keep the entry for correctly handling recorded TS).
127
    */
128
1.33k
    b_broken = b_broken && i_length && *psz_instring > 0x20;
129
130
1.33k
    if( b_broken )
131
0
        return FromCharset( "ISO_8859-1", psz_instring, i_length );
132
1.33k
    return vlc_from_EIT( psz_instring, i_length );
133
1.33k
}
134
135
288
#define attach_SI_decoders(i_pid, name, member) do {\
136
288
    ts_pid_t *pid = GetPID(p_sys, i_pid);\
137
288
    if ( PIDSetup( p_demux, TYPE_SI, pid, NULL ) )\
138
288
    {\
139
288
        if( !ts_attach_SI_Tables_Decoders( pid ) )\
140
288
        {\
141
0
            msg_Err( p_demux, "Can't attach SI table decoders for pid %d", i_pid );\
142
0
            PIDRelease( p_demux, pid );\
143
0
        }\
144
288
        else\
145
288
        {\
146
288
            sdt->u.p_si->member = pid;\
147
288
            SetPIDFilter( p_demux->p_sys, pid, true );\
148
288
            msg_Dbg( p_demux, "  * pid=%d listening for "name, i_pid );\
149
288
        }\
150
288
    }\
151
288
    } while(0)\
152
153
static void SDTCallBack( void *opaque, dvbpsi_sdt_t *p_sdt )
154
266
{
155
266
    demux_t              *p_demux = opaque;
156
266
    demux_sys_t          *p_sys = p_demux->p_sys;
157
266
    ts_pid_t             *sdt = GetPID(p_sys, TS_SI_SDT_PID);
158
266
    ts_pat_t             *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat;
159
266
    dvbpsi_sdt_service_t *p_srv;
160
161
266
    msg_Dbg( p_demux, "SDTCallBack called" );
162
163
266
    if( p_sys->es_creation != CREATE_ES ||
164
266
       !p_sdt->b_current_next ||
165
266
        p_sdt->i_version == sdt->u.p_si->p_ctx->i_version )
166
122
    {
167
122
        dvbpsi_sdt_delete( p_sdt );
168
122
        return;
169
122
    }
170
171
    /* First callback */
172
144
    if( sdt->u.p_si->p_ctx->i_version == -1 )
173
144
    {
174
144
        attach_SI_decoders( TS_SI_EIT_PID, "EIT", eitpid );
175
144
        attach_SI_decoders( TS_SI_TDT_PID, "TDT", tdtpid );
176
144
        if( p_sys->standard == TS_STANDARD_ARIB )
177
0
            attach_SI_decoders( TS_ARIB_CDT_PID, "CDT", cdtpid );
178
144
    }
179
180
181
144
    msg_Dbg( p_demux, "new SDT ts_id=%"PRIu16" version=%"PRIu8" current_next=%d "
182
144
             "network_id=%"PRIu16,
183
144
             p_sdt->i_extension,
184
144
             p_sdt->i_version, p_sdt->b_current_next,
185
144
             p_sdt->i_network_id );
186
187
144
    p_sys->b_broken_charset = false;
188
189
824
    for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
190
680
    {
191
680
        ts_pmt_t            *p_pmt = ts_pat_Get_pmt( p_pat, p_srv->i_service_id );
192
680
        vlc_meta_t          *p_meta;
193
680
        dvbpsi_descriptor_t *p_dr;
194
195
680
        const char *psz_type = NULL;
196
680
        const char *psz_status = NULL;
197
198
680
        msg_Dbg( p_demux, "  * service id=%"PRIu16" eit schedule=%d present=%d "
199
680
                 "running=%"PRIu8" free_ca=%d",
200
680
                 p_srv->i_service_id, p_srv->b_eit_schedule,
201
680
                 p_srv->b_eit_present, p_srv->i_running_status,
202
680
                 p_srv->b_free_ca );
203
204
680
        if( p_sys->vdr.i_service && p_srv->i_service_id != p_sys->vdr.i_service )
205
5
        {
206
5
            msg_Dbg( p_demux, "  * service id=%d skipped (not declared in vdr header)",
207
5
                     p_sys->vdr.i_service );
208
5
            continue;
209
5
        }
210
211
675
        p_meta = vlc_meta_New();
212
1.34k
        for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
213
665
        {
214
665
            if( p_dr->i_tag == 0x48 )
215
665
            {
216
665
                static const char *ppsz_type[17] = {
217
665
                    "Reserved",
218
665
                    "Digital television service",
219
665
                    "Digital radio sound service",
220
665
                    "Teletext service",
221
665
                    "NVOD reference service",
222
665
                    "NVOD time-shifted service",
223
665
                    "Mosaic service",
224
665
                    "PAL coded signal",
225
665
                    "SECAM coded signal",
226
665
                    "D/D2-MAC",
227
665
                    "FM Radio",
228
665
                    "NTSC coded signal",
229
665
                    "Data broadcast service",
230
665
                    "Reserved for Common Interface Usage",
231
665
                    "RCS Map (see EN 301 790 [35])",
232
665
                    "RCS FLS (see EN 301 790 [35])",
233
665
                    "DVB MHP service"
234
665
                };
235
665
                dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
236
665
                char *str1 = NULL;
237
665
                char *str2 = NULL;
238
239
                /* Workarounds for broadcasters with broken EPG */
240
241
665
                if( p_sdt->i_network_id == 133 )
242
0
                    p_sys->b_broken_charset = true;  /* SKY DE & BetaDigital use ISO8859-1 */
243
244
                /* List of providers using ISO8859-1 */
245
665
                static const char ppsz_broken_providers[][8] = {
246
665
                    "CSAT",     /* CanalSat FR */
247
665
                    "GR1",      /* France televisions */
248
665
                    "MULTI4",   /* NT1 */
249
665
                    "MR5",      /* France 2/M6 HD */
250
665
                    ""
251
665
                };
252
3.32k
                for( int i = 0; *ppsz_broken_providers[i]; i++ )
253
2.66k
                {
254
2.66k
                    const size_t i_length = strlen(ppsz_broken_providers[i]);
255
2.66k
                    if( pD->i_service_provider_name_length == i_length &&
256
1.33k
                        !strncmp( (char *)pD->i_service_provider_name, ppsz_broken_providers[i], i_length ) )
257
0
                        p_sys->b_broken_charset = true;
258
2.66k
                }
259
260
                /* FIXME: Digital+ ES also uses ISO8859-1 */
261
262
665
                str1 = EITConvertToUTF8(p_demux,
263
665
                                        pD->i_service_provider_name,
264
665
                                        pD->i_service_provider_name_length,
265
665
                                        p_sys->b_broken_charset );
266
665
                str2 = EITConvertToUTF8(p_demux,
267
665
                                        pD->i_service_name,
268
665
                                        pD->i_service_name_length,
269
665
                                        p_sys->b_broken_charset );
270
271
665
                msg_Dbg( p_demux, "    - type=%"PRIu8" provider=%s name=%s",
272
665
                         pD->i_service_type, str1, str2 );
273
274
665
                if( !str2 || strcmp( "Service01", str2 ) ) /* Skip bogus libav/ffmpeg SDT */
275
665
                {
276
665
                    vlc_meta_SetTitle( p_meta, str2 );
277
665
                    vlc_meta_SetPublisher( p_meta, str1 );
278
665
                    if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 )
279
0
                        psz_type = ppsz_type[pD->i_service_type];
280
665
                }
281
665
                free( str1 );
282
665
                free( str2 );
283
665
            }
284
0
            else if( p_sys->standard == TS_STANDARD_ARIB &&
285
0
                     p_dr->i_tag == TS_ARIB_DR_LOGO_TRANSMISSION && p_pmt )
286
0
            {
287
0
                ts_arib_logo_dr_t *p_logodr = ts_arib_logo_dr_Decode( p_dr->p_data, p_dr->i_length );
288
0
                if( p_logodr )
289
0
                {
290
0
                    if( p_logodr->i_transmission_mode == 0 )
291
0
                    {
292
0
                        p_pmt->arib.i_logo_id = p_logodr->i_logo_id;
293
0
                        p_pmt->arib.i_download_id = p_logodr->i_download_data_id;
294
0
                    }
295
0
                    else if( p_logodr->i_transmission_mode == 1 )
296
0
                    {
297
0
                        p_pmt->arib.i_logo_id = p_logodr->i_logo_id;
298
0
                    }
299
0
                    else /* TODO simple logo identifier */
300
0
                    {
301
302
0
                    }
303
304
0
                    if( p_pmt->arib.i_logo_id > -1 )
305
0
                    {
306
0
                        char *psz_name;
307
0
                        if( asprintf( &psz_name, "attachment://onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]",
308
0
                                      p_sdt->i_network_id, p_logodr->i_logo_id,
309
0
                                      TS_ARIB_LOGO_TYPE_HD_LARGE ) > -1 )
310
0
                        {
311
0
                            vlc_meta_SetArtURL( p_meta, psz_name );
312
0
                            vlc_meta_SetExtra( p_meta, "ARTURL", psz_name );
313
0
                            free( psz_name );
314
0
                        }
315
0
                    }
316
317
0
                    ts_arib_logo_dr_Delete( p_logodr );
318
0
                }
319
0
            }
320
665
        }
321
322
675
        if( p_srv->i_running_status >= 0x01 && p_srv->i_running_status <= 0x04 )
323
670
        {
324
670
            static const char *ppsz_status[5] = {
325
670
                "Unknown",
326
670
                "Not running",
327
670
                "Starts in a few seconds",
328
670
                "Pausing",
329
670
                "Running"
330
670
            };
331
670
            psz_status = ppsz_status[p_srv->i_running_status];
332
670
        }
333
334
675
        if( psz_type )
335
0
            vlc_meta_SetExtra( p_meta, "Type", psz_type );
336
675
        if( psz_status )
337
670
            vlc_meta_SetExtra( p_meta, "Status", psz_status );
338
339
675
        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META,
340
675
                        p_srv->i_service_id, p_meta );
341
675
        vlc_meta_Delete( p_meta );
342
675
    }
343
344
144
    sdt->u.p_si->p_ctx->i_version = p_sdt->i_version;
345
144
    dvbpsi_sdt_delete( p_sdt );
346
144
}
347
348
static void EITDecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d )
349
3
{
350
3
    const int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 );
351
3
    const int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 );
352
3
    const int c = ( mp == 14 || mp == 15 ) ? 1 : 0;
353
354
3
    *p_y = 1900 + yp + c*1;
355
3
    *p_m = mp - 1 - c*12;
356
3
    *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001);
357
3
}
358
9
#define CVT_FROM_BCD(v) ((((v) >> 4)&0xf)*10 + ((v)&0xf))
359
static int64_t EITConvertStartTime( uint64_t i_date )
360
3
{
361
3
    const int i_mjd = i_date >> 24;
362
3
    struct tm tm;
363
364
3
    tm.tm_hour = CVT_FROM_BCD(i_date >> 16);
365
3
    tm.tm_min  = CVT_FROM_BCD(i_date >>  8);
366
3
    tm.tm_sec  = CVT_FROM_BCD(i_date      );
367
368
    /* if all 40 bits are 1, the start is unknown */
369
3
    if( i_date == UINT64_C(0xffffffffff) )
370
0
        return -1;
371
372
3
    EITDecodeMjd( i_mjd, &tm.tm_year, &tm.tm_mon, &tm.tm_mday );
373
3
    tm.tm_year -= 1900;
374
3
    tm.tm_mon--;
375
3
    tm.tm_isdst = 0;
376
377
3
    return timegm( &tm );
378
3
}
379
static int EITConvertDuration( uint32_t i_duration )
380
0
{
381
0
    return CVT_FROM_BCD(i_duration >> 16) * 3600 +
382
0
           CVT_FROM_BCD(i_duration >> 8 ) * 60 +
383
0
           CVT_FROM_BCD(i_duration      );
384
0
}
385
#undef CVT_FROM_BCD
386
387
static void TDTCallBack( void *opaque, dvbpsi_tot_t *p_tdt )
388
3
{
389
3
    demux_t            *p_demux = opaque;
390
3
    demux_sys_t        *p_sys = p_demux->p_sys;
391
392
393
3
    p_sys->i_network_time = EITConvertStartTime( p_tdt->i_utc_time );
394
3
    p_sys->i_network_time_update = time(NULL);
395
3
    if( p_sys->standard == TS_STANDARD_ARIB )
396
0
    {
397
        /* All ARIB-B10 times are in JST time, where DVB is UTC. (spec being a fork)
398
           DVB TOT should include DTS offset in descriptor 0x58 (including DST),
399
           but as there's no DST in JAPAN (since Showa 27/1952)
400
           and considering that no-one seems to send TDT or desc 0x58,
401
           falling back on fixed offset is safe */
402
0
        p_sys->i_network_time += 9 * 3600;
403
0
    }
404
405
    /* Because libdvbpsi is broken and deduplicating timestamp tables,
406
     * we need to reset it to get next timestamp callback */
407
3
    ts_pid_t *pid = ts_pid_Get( &p_sys->pids, TS_SI_TDT_PID );
408
3
    dvbpsi_decoder_reset( pid->u.p_si->p_ctx->p_handle->p_decoder, true );
409
3
    dvbpsi_tot_delete(p_tdt);
410
411
3
    es_out_Control( p_demux->out, ES_OUT_SET_EPG_TIME, (int64_t) p_sys->i_network_time );
412
3
}
413
414
static void EITExtractDrDescItems( demux_t *p_demux, const dvbpsi_extended_event_dr_t *pE,
415
                                   vlc_epg_event_t *p_evt )
416
0
{
417
0
    demux_sys_t *p_sys = p_demux->p_sys;
418
419
0
    if( pE->i_entry_count )
420
0
    {
421
0
        char **ppsz_prev = NULL;
422
        /* Continued items from previous descriptor (ARIB) */
423
0
        if( p_evt->i_description_items > 0 )
424
0
            ppsz_prev = &p_evt->description_items[p_evt->i_description_items - 1].psz_value;
425
426
0
        for( int i = 0; i < pE->i_entry_count; i++ )
427
0
        {
428
0
            char *psz_key = NULL;
429
            /* Continued items have NULL key */
430
0
            const bool b_appending = ( pE->i_item_description_length[i] == 0 );
431
0
            if( !b_appending )
432
0
            {
433
0
                void *p_realloc = NULL;
434
0
                if( (size_t)p_evt->i_description_items < SIZE_MAX / sizeof(*p_evt->description_items) )
435
0
                {
436
0
                    p_realloc = realloc( p_evt->description_items,
437
0
                                        (p_evt->i_description_items + 1) *
438
0
                                         sizeof(*p_evt->description_items) );
439
0
                }
440
0
                if( !p_realloc )
441
0
                {
442
0
                    free( psz_key );
443
0
                    break;
444
0
                }
445
0
                p_evt->description_items = p_realloc;
446
447
0
                psz_key = EITConvertToUTF8( p_demux,
448
0
                                            pE->i_item_description[i],
449
0
                                            pE->i_item_description_length[i],
450
0
                                            p_sys->b_broken_charset );
451
0
                if( !psz_key )
452
0
                {
453
0
                    ppsz_prev = NULL;
454
0
                    continue;
455
0
                }
456
0
            }
457
0
            else if( ppsz_prev == NULL )
458
0
                continue;
459
460
0
            char *psz_itm = EITConvertToUTF8( p_demux,
461
0
                                              pE->i_item[i], pE->i_item_length[i],
462
0
                                              p_sys->b_broken_charset );
463
0
            if( !psz_itm )
464
0
            {
465
0
                free( psz_key );
466
0
                ppsz_prev = NULL;
467
0
                continue;
468
0
            }
469
470
0
            msg_Dbg( p_demux, "       - desc='%s' item='%s'",
471
0
                     psz_key ? psz_key : "(null)", psz_itm );
472
0
            if( b_appending )
473
0
            {
474
                /* Continued items */
475
0
                size_t i_total = strlen(*ppsz_prev) + strlen(psz_itm) + 1;
476
0
                char *psz_realloc = realloc( *ppsz_prev, i_total );
477
0
                if( psz_realloc )
478
0
                {
479
0
                    *ppsz_prev = psz_realloc;
480
0
                    strcat( *ppsz_prev, psz_itm );
481
0
                }
482
0
                free( psz_itm );
483
0
            }
484
0
            else
485
0
            {
486
0
                p_evt->description_items[p_evt->i_description_items].psz_key = psz_key;
487
0
                p_evt->description_items[p_evt->i_description_items].psz_value = psz_itm;
488
0
                ppsz_prev = &p_evt->description_items[p_evt->i_description_items].psz_value;
489
0
                p_evt->i_description_items++;
490
0
            }
491
0
        }
492
0
    }
493
0
}
494
495
static void EITCallBack( void *opaque, dvbpsi_eit_t *p_eit )
496
0
{
497
0
    demux_t            *p_demux = opaque;
498
0
    demux_sys_t        *p_sys = p_demux->p_sys;
499
0
    const dvbpsi_eit_event_t *p_evt;
500
0
    uint64_t i_runevt = 0;
501
0
    uint64_t i_fallbackevt = 0;
502
0
    vlc_epg_t *p_epg;
503
504
0
    msg_Dbg( p_demux, "EITCallBack called" );
505
0
    if( !p_eit->b_current_next )
506
0
    {
507
0
        dvbpsi_eit_delete( p_eit );
508
0
        return;
509
0
    }
510
511
0
    msg_Dbg( p_demux, "new EIT service_id=%"PRIu16" version=%"PRIu8" current_next=%d "
512
0
             "ts_id=%"PRIu16" network_id=%"PRIu16" segment_last_section_number=%"PRIu8" "
513
0
             "last_table_id=%"PRIu8,
514
0
             p_eit->i_extension,
515
0
             p_eit->i_version, p_eit->b_current_next,
516
0
             p_eit->i_ts_id, p_eit->i_network_id,
517
0
             p_eit->i_segment_last_section_number, p_eit->i_last_table_id );
518
519
    /* Use table ID for segmenting our EPG tables updates. 1 table id has 256 sections which
520
     * represents 8 segments of 32 sections each. Thus a max of 24 hours per table ID
521
     * (Should be even better with tableid+segmentid compound if dvbpsi would export segment id)
522
     * see TS 101 211, 4.1.4.2.1 */
523
0
    p_epg = vlc_epg_New( p_eit->i_table_id, p_eit->i_extension );
524
0
    if( !p_epg )
525
0
    {
526
0
        dvbpsi_eit_delete( p_eit );
527
0
        return;
528
0
    }
529
530
0
    for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next )
531
0
    {
532
0
        dvbpsi_descriptor_t *p_dr;
533
0
        int64_t i_start;
534
0
        int i_duration;
535
536
0
        i_start = EITConvertStartTime( p_evt->i_start_time );
537
0
        SI_DEBUG_TIMESHIFT(i_start);
538
0
        i_duration = EITConvertDuration( p_evt->i_duration );
539
540
        /* We have to fix ARIB-B10 as all timestamps are JST */
541
0
        if( p_sys->standard == TS_STANDARD_ARIB )
542
0
        {
543
            /* See comments on TDT callback */
544
0
            i_start += 9 * 3600;
545
0
        }
546
547
0
        msg_Dbg( p_demux, "  * event id=%"PRIu16" start_time:%"PRId64" duration=%d "
548
0
                          "running=%"PRIu8" free_ca=%d",
549
0
                 p_evt->i_event_id, i_start, i_duration,
550
0
                 p_evt->i_running_status, p_evt->b_free_ca );
551
552
        /* */
553
0
        if( i_start <= 0 )
554
0
            continue;
555
556
0
        vlc_epg_event_t *p_epgevt = vlc_epg_event_New( p_evt->i_event_id,
557
0
                                                       i_start, i_duration );
558
0
        if( !p_epgevt )
559
0
            continue;
560
561
0
        if( !vlc_epg_AddEvent( p_epg, p_epgevt ) )
562
0
        {
563
0
            vlc_epg_event_Delete( p_epgevt );
564
0
            continue;
565
0
        }
566
567
0
        for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
568
0
        {
569
0
            switch(p_dr->i_tag)
570
0
            {
571
0
            case 0x4d:
572
0
            {
573
0
                dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr );
574
575
                /* Only take first description, as we don't handle language-info
576
                   for epg atm*/
577
0
                if( pE )
578
0
                {
579
0
                    char **ppsz = &p_epgevt->psz_name;
580
0
                    free( *ppsz );
581
0
                    *ppsz = EITConvertToUTF8( p_demux,
582
0
                                              pE->i_event_name, pE->i_event_name_length,
583
0
                                              p_sys->b_broken_charset );
584
0
                    ppsz = &p_epgevt->psz_short_description;
585
0
                    free( *ppsz );
586
0
                    *ppsz = EITConvertToUTF8( p_demux,
587
0
                                              pE->i_text, pE->i_text_length,
588
0
                                              p_sys->b_broken_charset );
589
0
                    msg_Dbg( p_demux, "    - short event lang=%3.3s '%s' : '%s'",
590
0
                             pE->i_iso_639_code, p_epgevt->psz_name, *ppsz );
591
0
                }
592
0
            }
593
0
                break;
594
595
0
            case 0x4e:
596
0
            {
597
0
                dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr );
598
0
                if( pE )
599
0
                {
600
0
                    msg_Dbg( p_demux, "    - extended event lang=%3.3s [%"PRIu8"/%"PRIu8"]",
601
0
                             pE->i_iso_639_code,
602
0
                             pE->i_descriptor_number, pE->i_last_descriptor_number );
603
604
0
                    if( pE->i_text_length > 0 )
605
0
                    {
606
0
                        char *psz_text = EITConvertToUTF8( p_demux,
607
0
                                                           pE->i_text, pE->i_text_length,
608
0
                                                           p_sys->b_broken_charset );
609
0
                        if( psz_text )
610
0
                        {
611
0
                            msg_Dbg( p_demux, "       - text='%s'", psz_text );
612
613
0
                            if( p_epgevt->psz_description )
614
0
                            {
615
0
                                size_t i_total = strlen( p_epgevt->psz_description ) + strlen( psz_text ) + 1;
616
0
                                char *psz_realloc = realloc( p_epgevt->psz_description, i_total );
617
0
                                if( psz_realloc )
618
0
                                {
619
0
                                    p_epgevt->psz_description = psz_realloc;
620
0
                                    strcat( psz_realloc, psz_text );
621
0
                                }
622
0
                                free( psz_text );
623
0
                            }
624
0
                            else
625
0
                            {
626
0
                                p_epgevt->psz_description = psz_text;
627
0
                            }
628
0
                        }
629
0
                    }
630
631
0
                    EITExtractDrDescItems( p_demux, pE, p_epgevt );
632
0
                }
633
0
            }
634
0
                break;
635
636
0
            case 0x55:
637
0
            {
638
0
                dvbpsi_parental_rating_dr_t *pR = dvbpsi_DecodeParentalRatingDr( p_dr );
639
0
                if ( pR )
640
0
                {
641
0
                    int i_min_age = 0;
642
0
                    for ( int i = 0; i < pR->i_ratings_number; i++ )
643
0
                    {
644
0
                        const dvbpsi_parental_rating_t *p_rating = & pR->p_parental_rating[ i ];
645
0
                        if ( p_rating->i_rating > 0x00 && p_rating->i_rating <= 0x0F )
646
0
                        {
647
0
                            if ( p_rating->i_rating + 3 > i_min_age )
648
0
                                i_min_age = p_rating->i_rating + 3;
649
0
                            msg_Dbg( p_demux, "    - parental control set to %d years",
650
0
                                     i_min_age );
651
0
                        }
652
0
                    }
653
0
                    p_epgevt->i_rating = i_min_age;
654
0
                }
655
0
            }
656
0
                break;
657
658
0
            default:
659
0
                msg_Dbg( p_demux, "    - event unknown dr 0x%"PRIx8"(%"PRIu8")", p_dr->i_tag, p_dr->i_tag );
660
0
                break;
661
0
            }
662
0
        }
663
664
0
        switch ( p_evt->i_running_status )
665
0
        {
666
0
            case TS_SI_RUNSTATUS_RUNNING:
667
0
                if( i_runevt == 0 )
668
0
                    i_runevt = i_start;
669
0
                break;
670
0
            case TS_SI_RUNSTATUS_UNDEFINED:
671
0
            {
672
0
                if( i_fallbackevt == 0 &&
673
0
                    i_start <= p_sys->i_network_time &&
674
0
                    p_sys->i_network_time < i_start + i_duration )
675
0
                    i_fallbackevt = i_start;
676
0
                break;
677
0
            }
678
0
            default:
679
0
                break;
680
0
        }
681
0
    }
682
683
    /* Update "now playing" field */
684
0
    if( i_runevt || i_fallbackevt )
685
0
        vlc_epg_SetCurrent( p_epg, (i_runevt) ? i_runevt : i_fallbackevt );
686
687
0
    if( p_epg->i_event > 0 )
688
0
    {
689
0
        if( p_epg->b_present && p_epg->p_current )
690
0
        {
691
0
            ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat;
692
0
            ts_pmt_t *p_pmt = ts_pat_Get_pmt(p_pat, p_eit->i_extension);
693
0
            if(p_pmt)
694
0
            {
695
0
                p_pmt->eit.i_event_start = p_epg->p_current->i_start;
696
0
                p_pmt->eit.i_event_length = p_epg->p_current->i_duration;
697
0
            }
698
0
        }
699
0
        p_epg->b_present = (p_eit->i_table_id == 0x4e);
700
0
        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, p_eit->i_extension, p_epg );
701
0
    }
702
0
    vlc_epg_Delete( p_epg );
703
704
0
    dvbpsi_eit_delete( p_eit );
705
0
}
706
707
static void ARIB_CDT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section,
708
                                  void *p_cdtpid )
709
0
{
710
0
    VLC_UNUSED(p_cdtpid);
711
0
    demux_t *p_demux = (demux_t *) p_handle->p_sys;
712
0
    demux_sys_t *p_sys = p_demux->p_sys;
713
0
    const ts_pat_t *p_pat = GetPID(p_sys, 0)->u.p_pat;
714
715
0
    while( p_section )
716
0
    {
717
0
        const uint8_t *p_data = p_section->p_payload_start;
718
0
        size_t i_data = p_section->p_payload_end - p_section->p_payload_start;
719
720
0
        if( i_data < (6U + 7 + 1) || p_data[2] != TS_ARIB_CDT_DATA_TYPE_LOGO )
721
0
            continue;
722
723
0
        uint16_t i_onid = (p_data[0] << 8) | p_data[1];
724
0
        uint16_t i_dr_len = ((p_data[3] & 0x0F) << 4) | p_data[4];
725
0
        if( i_data < i_dr_len + (6U + 7 + 1) )
726
0
            continue;
727
728
        /* STD-B21 A.5.4 (Japanese spec only) */
729
730
0
        const uint8_t *p_dmb = &p_data[5 + i_dr_len];
731
0
        size_t i_dmb = i_data - 5 - i_dr_len;
732
733
0
        while( i_dmb > 7 )
734
0
        {
735
0
            uint8_t i_logo_type = p_dmb[0];
736
0
            uint16_t i_logo_id = ((p_dmb[1] & 0x01) << 8) | p_dmb[2];
737
0
            uint16_t i_size = (p_dmb[5] << 8) | p_dmb[6];
738
739
0
            if( 7U + i_size > i_dmb )
740
0
                break;
741
742
0
            for( int i=0; i<p_pat->programs.i_size; i++ )
743
0
            {
744
0
                ts_pmt_t *p_pmt = p_pat->programs.p_elems[i]->u.p_pmt;
745
0
                if( p_pmt->arib.i_logo_id == i_logo_id && i_logo_type == TS_ARIB_LOGO_TYPE_HD_LARGE )
746
0
                {
747
0
                    char *psz_name;
748
0
                    if( asprintf( &psz_name, "onid[%"PRIx16"]_channel_logo_id[%"PRIx16"]q[%d]",
749
0
                                  i_onid, i_logo_id, i_logo_type ) > -1 )
750
0
                    {
751
0
                        uint8_t *p_png; size_t i_png;
752
0
                        if( !vlc_dictionary_has_key( &p_sys->attachments, psz_name ) &&
753
0
                            ts_arib_inject_png_palette( &p_dmb[7], i_size, &p_png, &i_png ) )
754
0
                        {
755
0
                            input_attachment_t *p_att = vlc_input_attachment_New(
756
0
                                                        psz_name, "image/png", NULL, p_png, i_png );
757
0
                            if( p_att )
758
0
                            {
759
0
                                vlc_dictionary_insert( &p_sys->attachments, psz_name, p_att );
760
0
                                p_sys->updates |= INPUT_UPDATE_META;
761
0
                            }
762
0
                            free( p_png );
763
0
                        }
764
0
                        free( psz_name );
765
0
                    }
766
0
                }
767
0
            }
768
769
0
            i_dmb -= 7 + i_size;
770
0
            p_dmb += 7 + i_size;
771
0
        }
772
773
0
        p_section = p_section->p_next;
774
0
    }
775
0
}
776
777
static void SINewTableCallBack( dvbpsi_t *h, uint8_t i_table_id,
778
                                uint16_t i_extension, void *p_pid_cbdata )
779
12.9k
{
780
12.9k
    assert( h );
781
12.9k
    ts_pid_t *p_pid = (ts_pid_t *) p_pid_cbdata;
782
12.9k
    demux_t *p_demux = (demux_t *) h->p_sys;
783
#if 0
784
    msg_Dbg( p_demux, "SINewTableCallback: table 0x%"PRIx8"(%"PRIu16") ext=0x%"PRIx16"(%"PRIu16")",
785
             i_table_id, i_table_id, i_extension, i_extension );
786
#endif
787
12.9k
    if( p_pid->i_pid == TS_SI_SDT_PID && i_table_id == 0x42 )
788
167
    {
789
167
        if( !dvbpsi_sdt_attach( h, i_table_id, i_extension, SDTCallBack, p_demux ) )
790
167
            msg_Err( p_demux, "SINewTableCallback: failed attaching SDTCallback" );
791
167
    }
792
12.7k
    else if( p_pid->i_pid == TS_SI_EIT_PID &&
793
2.23k
             ( i_table_id == 0x4e || /* Current/Following */
794
2.08k
               (i_table_id >= 0x50 && i_table_id <= 0x5f) ) ) /* Schedule */
795
200
    {
796
200
        if( !dvbpsi_eit_attach( h, i_table_id, i_extension,
797
200
                                EITCallBack, p_demux ) )
798
200
            msg_Err( p_demux, "SINewTableCallback: failed attaching EITCallback" );
799
200
    }
800
12.5k
    else if( p_pid->i_pid == TS_SI_TDT_PID &&
801
38
            (i_table_id == TS_SI_TDT_TABLE_ID || i_table_id == TS_SI_TOT_TABLE_ID) )
802
3
    {
803
3
        if( !dvbpsi_tot_attach( h, i_table_id, i_extension, TDTCallBack, p_demux ) )
804
3
            msg_Err( p_demux, "SINewTableCallback: failed attaching TDTCallback" );
805
3
    }
806
12.5k
    else if( p_pid->i_pid == TS_ARIB_CDT_PID && i_table_id == TS_ARIB_CDT_TABLE_ID )
807
0
    {
808
0
        if( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) h->p_decoder, i_table_id, i_extension ) == NULL &&
809
0
            !ts_dvbpsi_AttachRawSubDecoder( h, i_table_id, i_extension, ARIB_CDT_RawCallback, p_pid ) )
810
0
            msg_Err( p_demux, "SINewTableCallback: failed attaching ARIB_CDT_RawCallback" );
811
0
    }
812
12.9k
}
813
814
bool ts_attach_SI_Tables_Decoders( ts_pid_t *p_pid )
815
39.9k
{
816
39.9k
    if( p_pid->type != TYPE_SI )
817
0
        return false;
818
819
39.9k
    if( dvbpsi_decoder_present( p_pid->u.p_si->p_ctx->p_handle ) )
820
24.5k
        return true;
821
822
15.4k
    return dvbpsi_AttachDemux( p_pid->u.p_si->p_ctx->p_handle, SINewTableCallBack, p_pid );
823
39.9k
}
824
825
void ts_si_context_Delete( ts_si_context_t *p_ctx )
826
15.4k
{
827
15.4k
    if( dvbpsi_decoder_present( p_ctx->p_handle ) )
828
15.4k
        dvbpsi_DetachDemux( p_ctx->p_handle );
829
15.4k
    dvbpsi_delete( p_ctx->p_handle );
830
15.4k
    free( p_ctx );
831
15.4k
}
832
833
ts_si_context_t * ts_si_context_New( demux_t *p_demux )
834
15.4k
{
835
15.4k
    ts_si_context_t *p_ctx = malloc(sizeof(*p_ctx));
836
15.4k
    if(likely(p_ctx))
837
15.4k
    {
838
15.4k
        p_ctx->p_handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
839
15.4k
        if( !p_ctx->p_handle )
840
0
        {
841
0
            free( p_ctx );
842
0
            return NULL;
843
0
        }
844
15.4k
        p_ctx->p_handle->p_sys = (void *) p_demux;
845
15.4k
        p_ctx->i_version = -1;
846
15.4k
    }
847
15.4k
    return p_ctx;
848
15.4k
}