Coverage Report

Created: 2026-04-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_psip.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_psip.c : TS demux ATSC A65 PSIP handling
3
 *****************************************************************************
4
 * Copyright (C) 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
28
#ifndef _DVBPSI_DVBPSI_H_
29
 #include <dvbpsi/dvbpsi.h>
30
#endif
31
#ifndef _DVBPSI_DEMUX_H_
32
 #include <dvbpsi/demux.h>
33
#endif
34
#include <dvbpsi/descriptor.h>
35
#include <dvbpsi/atsc_mgt.h>
36
#include <dvbpsi/atsc_vct.h>
37
#include <dvbpsi/atsc_eit.h>
38
#include <dvbpsi/atsc_ett.h>
39
#include <dvbpsi/atsc_stt.h>
40
#include <dvbpsi/dr_a0.h>
41
#include "../../mux/mpeg/dvbpsi_compat.h" /* dvbpsi_messages */
42
/* Custom decoders */
43
#include <dvbpsi/psi.h>
44
#include "ts_decoders.h"
45
#include "ts_psip_dvbpsi_fixes.h"
46
47
#include "timestamps.h"
48
#include "ts_pid.h"
49
#include "ts.h"
50
#include "ts_streams_private.h"
51
#include "ts_scte.h"
52
53
#include "ts_psip.h"
54
55
#include "../../codec/atsc_a65.h"
56
#include "../../codec/scte18.h"
57
58
#include <assert.h>
59
60
static inline char *grab_notempty( char **ppsz )
61
0
{
62
0
    char *psz_ret = NULL;
63
0
    if( *ppsz && **ppsz )
64
0
    {
65
0
        psz_ret = *ppsz;
66
0
        *ppsz = NULL;
67
0
    }
68
0
    return psz_ret;
69
0
}
70
71
/*
72
 * Decoders activation order due to dependencies,
73
 * and because callbacks will be fired once per MGT/VCT version
74
 * STT(ref by EIT,EAS) -> MGT
75
 * MGT -> VCT,EAS,EIT/ETT
76
 */
77
78
struct ts_psip_context_t
79
{
80
    dvbpsi_t *p_handle;
81
    int       i_version;
82
    dvbpsi_atsc_mgt_t *p_mgt; /* Used to match (EITx,ETTx)<->PIDn */
83
    dvbpsi_atsc_stt_t *p_stt; /* Time reference for EIT/EAS */
84
    dvbpsi_atsc_vct_t *p_vct; /* Required for EIT vchannel -> program remapping */
85
    atsc_a65_handle_t *p_a65; /* Shared Handle to avoid iconv reopens */
86
    uint16_t i_tabletype; /* Only used by EIT/ETT pid */
87
    DECL_ARRAY(dvbpsi_atsc_ett_t *) etts; /* For ETT pid, used on new EIT update */
88
    DECL_ARRAY(dvbpsi_atsc_eit_t *) eits; /* For EIT pid, used on new ETT update */
89
};
90
91
static void ATSC_Detach_Dvbpsi_Decoders( dvbpsi_t *p_handle );
92
93
void ts_psip_Packet_Push( ts_pid_t *p_pid, const uint8_t *p_pktbuffer )
94
97
{
95
97
    ts_psip_context_t *p_ctx = p_pid->u.p_psip->p_ctx;
96
97
    if( p_ctx->p_handle->p_decoder && likely(p_pid->type == TYPE_PSIP) )
97
97
        dvbpsi_packet_push( p_ctx->p_handle, (uint8_t *) p_pktbuffer );
98
97
}
99
100
ts_psip_context_t * ts_psip_context_New( demux_t *p_demux )
101
95
{
102
95
    ts_psip_context_t *p_ctx = malloc(sizeof(*p_ctx));
103
95
    if(likely(p_ctx))
104
95
    {
105
95
        p_ctx->p_handle = dvbpsi_new( &dvbpsi_messages, DVBPSI_MSG_DEBUG );
106
95
        if( !p_ctx->p_handle )
107
0
        {
108
0
            free( p_ctx );
109
0
            return NULL;
110
0
        }
111
95
        p_ctx->p_handle->p_sys = (void *) p_demux;
112
95
        p_ctx->i_version = -1;
113
95
        p_ctx->p_mgt = NULL;
114
95
        p_ctx->p_stt = NULL;
115
95
        p_ctx->p_vct = NULL;
116
95
        p_ctx->p_a65 = NULL;
117
95
        p_ctx->i_tabletype = 0;
118
95
        ARRAY_INIT(p_ctx->etts);
119
95
        ARRAY_INIT(p_ctx->eits);
120
95
    }
121
95
    return p_ctx;
122
95
}
123
124
void ts_psip_context_Delete( ts_psip_context_t *p_ctx )
125
95
{
126
95
    assert( !p_ctx->p_mgt || !p_ctx->etts.i_size );
127
95
    assert( !p_ctx->p_vct || !p_ctx->eits.i_size );
128
129
95
    ATSC_Detach_Dvbpsi_Decoders( p_ctx->p_handle );
130
95
    dvbpsi_delete( p_ctx->p_handle );
131
132
95
    if( p_ctx->p_mgt )
133
0
        dvbpsi_atsc_DeleteMGT( p_ctx->p_mgt );
134
95
    if( p_ctx->p_stt )
135
0
        dvbpsi_atsc_DeleteSTT( p_ctx->p_stt );
136
95
    if ( p_ctx->p_vct )
137
0
        dvbpsi_atsc_DeleteVCT( p_ctx->p_vct );
138
95
    if( p_ctx->p_a65 )
139
0
        atsc_a65_handle_Release( p_ctx->p_a65 );
140
    /* Things only used for ETT/EIT */
141
95
    for( int i=0; i<p_ctx->etts.i_size; i++ )
142
0
        dvbpsi_atsc_DeleteETT( p_ctx->etts.p_elems[i] );
143
95
    for( int i=0; i<p_ctx->eits.i_size; i++ )
144
0
        dvbpsi_atsc_DeleteEIT( p_ctx->eits.p_elems[i] );
145
95
    ARRAY_RESET( p_ctx->etts );
146
95
    ARRAY_RESET( p_ctx->eits );
147
95
    free( p_ctx );
148
95
}
149
150
static ts_pid_t *ATSC_GetSiblingxTTPID( ts_pid_list_t *p_list, const dvbpsi_atsc_mgt_t *p_mgt, ts_psip_t *p_psip )
151
0
{
152
0
    uint16_t i_lookup;
153
0
    assert( p_psip->p_ctx->i_tabletype );
154
0
    if( p_psip->p_ctx->i_tabletype >= ATSC_TABLE_TYPE_ETT_0 )
155
0
        i_lookup = p_psip->p_ctx->i_tabletype - ATSC_TABLE_TYPE_ETT_0 + ATSC_TABLE_TYPE_EIT_0;
156
0
    else
157
0
        i_lookup = p_psip->p_ctx->i_tabletype - ATSC_TABLE_TYPE_EIT_0 + ATSC_TABLE_TYPE_ETT_0;
158
159
0
    for( const dvbpsi_atsc_mgt_table_t *p_tab = p_mgt->p_first_table;
160
0
                                        p_tab; p_tab = p_tab->p_next )
161
0
    {
162
0
        if( p_tab->i_table_type == i_lookup )
163
0
            return ts_pid_Get( p_list, p_tab->i_table_type_pid );
164
0
    }
165
0
    return NULL;
166
0
}
167
168
static inline uint32_t toETMId( uint16_t i_vchannel, uint16_t i_event_id )
169
0
{
170
0
    return (i_vchannel << 16) | (i_event_id << 2) | 0x02;
171
0
}
172
173
static inline void fromETMId( uint32_t i_etm_id, uint16_t *pi_vchannel, uint16_t *pi_event_id )
174
0
{
175
0
    *pi_vchannel = i_etm_id >> 16;
176
0
    *pi_event_id = (i_etm_id & 0xFFFF) >> 2;
177
0
}
178
179
static const dvbpsi_atsc_ett_t * ATSC_ETTFindByETMId( ts_psip_context_t *p_ettctx, uint32_t i_etm_id, uint8_t i_version )
180
0
{
181
0
    int i;
182
0
    ARRAY_BSEARCH( p_ettctx->etts, ->i_etm_id, uint32_t, i_etm_id, i );
183
0
    if( i != -1 && p_ettctx->etts.p_elems[i]->i_version == i_version )
184
0
        return p_ettctx->etts.p_elems[i];
185
0
    return NULL;
186
0
}
187
188
static const dvbpsi_atsc_eit_event_t * ATSC_EventFindByETMId( ts_psip_context_t *p_eitctx,
189
                                                              uint32_t i_etm_id, uint8_t i_version )
190
0
{
191
0
    uint16_t i_vchannel_id, i_event_id;
192
0
    fromETMId( i_etm_id, &i_vchannel_id, &i_event_id );
193
194
0
    for( int i=0; i<p_eitctx->eits.i_size; i++ )
195
0
    {
196
0
        dvbpsi_atsc_eit_t *p_eit = p_eitctx->eits.p_elems[i];
197
0
        if( p_eit->i_version != i_version || p_eit->i_source_id != i_vchannel_id )
198
0
            continue;
199
200
0
        for( const dvbpsi_atsc_eit_event_t *p_evt = p_eit->p_first_event;
201
0
                                            p_evt ; p_evt = p_evt->p_next )
202
0
        {
203
0
            if( p_evt->i_event_id == i_event_id )
204
0
                return p_evt;
205
0
        }
206
0
    }
207
0
    return NULL;
208
0
}
209
210
static void ATSC_EITInsert( ts_psip_context_t *p_ctx, dvbpsi_atsc_eit_t *p_eit )
211
0
{
212
0
    for( int i=0; i<p_ctx->eits.i_size; i++ )
213
0
    {
214
0
        dvbpsi_atsc_eit_t *p_cur_eit = p_ctx->eits.p_elems[i];
215
0
        if( p_cur_eit->i_source_id == p_eit->i_source_id )
216
0
        {
217
0
            dvbpsi_atsc_DeleteEIT( p_cur_eit ); /* Updated version */
218
0
            p_ctx->eits.p_elems[i] = p_eit;
219
0
            return;
220
0
        }
221
0
    }
222
0
    ARRAY_APPEND( p_ctx->eits, p_eit );
223
0
}
224
225
static void ATSC_CleanETTByChannelVersion( ts_psip_context_t *p_ctx, uint16_t i_channel, uint8_t i_version )
226
0
{
227
0
    int i=0;
228
0
    while( i<p_ctx->etts.i_size )
229
0
    {
230
0
        dvbpsi_atsc_ett_t *p = p_ctx->etts.p_elems[i];
231
0
        uint16_t i_curchan = p->i_etm_id >> 16;
232
0
        if( i_channel <  i_curchan )
233
0
            break; /* because ordered */
234
0
        if( i_curchan == i_channel && p->i_version != i_version )
235
0
        {
236
0
            dvbpsi_atsc_DeleteETT( p );
237
0
            ARRAY_REMOVE( p_ctx->etts, i );
238
0
        }
239
0
        else i++;
240
0
    }
241
0
}
242
243
static void ATSC_InsertETTOrdered( ts_psip_context_t *p_ctx, dvbpsi_atsc_ett_t *p_ett )
244
0
{
245
0
    int i=0;
246
0
    for( ; i<p_ctx->etts.i_size; i++ )
247
0
    {
248
0
        dvbpsi_atsc_ett_t *p = p_ctx->etts.p_elems[i];
249
0
        if( p->i_etm_id >= p_ett->i_etm_id )
250
0
        {
251
0
            if( p->i_etm_id == p_ett->i_etm_id )
252
0
            {
253
0
                dvbpsi_atsc_DeleteETT( p );
254
0
                p_ctx->etts.p_elems[i] = p_ett;
255
0
                return;
256
0
            }
257
0
            break;
258
0
        }
259
0
    }
260
0
    ARRAY_INSERT( p_ctx->etts, p_ett, i );
261
0
}
262
263
static bool ATSC_TranslateVChannelToProgram( const dvbpsi_atsc_vct_t *p_vct,
264
                                             uint16_t i_channel, uint16_t *pi_program )
265
0
{
266
0
    for( const dvbpsi_atsc_vct_channel_t *p_channel = p_vct->p_first_channel;
267
0
                                          p_channel; p_channel = p_channel->p_next )
268
0
    {
269
0
        if( p_channel->i_source_id == i_channel )
270
0
        {
271
0
            *pi_program = p_channel->i_program_number;
272
0
            return true;
273
0
        }
274
0
    }
275
0
    return false;
276
0
}
277
278
static void ATSC_NewTable_Callback( dvbpsi_t *p_dvbpsi, uint8_t i_table_id,
279
                                    uint16_t i_extension, void *p_pid );
280
281
/* Just Hook a base demux, and let NewTableCallback handle decoders creation */
282
static bool ATSC_Ready_SubDecoders( dvbpsi_t *p_handle, void *p_cb_pid )
283
261
{
284
261
    if( !dvbpsi_decoder_present( p_handle ) )
285
95
        return dvbpsi_AttachDemux( p_handle, ATSC_NewTable_Callback, p_cb_pid );
286
166
    return true;
287
261
}
288
289
static void ATSC_Detach_Dvbpsi_Decoders( dvbpsi_t *p_handle )
290
95
{
291
95
    if( dvbpsi_decoder_present( p_handle ) )
292
95
        dvbpsi_DetachDemux( p_handle );
293
95
}
294
295
#define ATSC_ATTACH( handle, type, table, extension, pid ) \
296
0
    ( ATSC_Ready_SubDecoders( handle, pid ) &&\
297
0
      ( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) handle->p_decoder, table, extension ) ||\
298
0
        dvbpsi_atsc_Attach ## type( handle, table, extension, ATSC_ ## type ## _Callback, pid ) ) )
299
300
#define ATSC_ATTACH_WITH_FIXED_DECODER( handle, type, table, extension, pid ) \
301
261
    ( ATSC_Ready_SubDecoders( handle, pid ) &&\
302
261
        ( dvbpsi_demuxGetSubDec( (dvbpsi_demux_t *) handle->p_decoder, table, extension ) ||\
303
261
          ts_dvbpsi_AttachRawSubDecoder( handle, table, extension, ATSC_ ## type ## _RawCallback, pid ) ) )
304
305
static const char * const rgpsz_ATSC_A53_service_types[] =
306
{
307
    "Analog Television",
308
    "ATSC Digital Television",
309
    "ATSC Audio",
310
    "ATSC Data Only Service",
311
    "ATSC Software Download Service",
312
};
313
314
static const char * ATSC_A53_get_service_type( uint8_t i_type )
315
0
{
316
0
    if( i_type == 0 || i_type > 5 )
317
0
        return NULL;
318
0
    return rgpsz_ATSC_A53_service_types[i_type - 1];
319
0
}
320
321
#ifndef ATSC_DEBUG_EIT
322
 #define EIT_DEBUG_TIMESHIFT(t)
323
#else
324
 /* Define static time var used as anchor to current time to offset all eit entries */
325
 static time_t i_eit_debug_offset = 0;
326
 #define EIT_DEBUG_TIMESHIFT(t) \
327
    do {\
328
        if( i_eit_debug_offset == 0 )\
329
            i_eit_debug_offset = time(NULL) - t;\
330
        t = t + i_eit_debug_offset;\
331
    } while(0);
332
#endif
333
334
static vlc_epg_event_t * ATSC_CreateVLCEPGEvent( demux_t *p_demux, ts_psip_context_t *p_basectx,
335
                                                 const dvbpsi_atsc_eit_event_t *p_evt,
336
                                                 const dvbpsi_atsc_ett_t *p_ett )
337
0
{
338
0
#ifndef ATSC_DEBUG_EIT
339
0
    VLC_UNUSED(p_demux);
340
0
#endif
341
0
    char *psz_title = atsc_a65_Decode_multiple_string( p_basectx->p_a65,
342
0
                                                       p_evt->i_title, p_evt->i_title_length );
343
0
    char *psz_shortdesc_text = NULL;
344
0
    char *psz_longdesc_text = NULL;
345
0
    vlc_epg_event_t *p_epgevt = NULL;
346
347
0
    time_t i_start = atsc_a65_GPSTimeToEpoch( p_evt->i_start_time, p_basectx->p_stt->i_gps_utc_offset );
348
0
    EIT_DEBUG_TIMESHIFT( i_start );
349
350
0
    for( const dvbpsi_descriptor_t *p_dr = p_evt->p_first_descriptor;
351
0
                                    p_dr; p_dr = p_dr->p_next )
352
0
    {
353
0
        switch( p_dr->i_tag )
354
0
        {
355
0
            case ATSC_DESCRIPTOR_CONTENT_ADVISORY:
356
0
            {
357
0
                const uint8_t *p_data = p_dr->p_data;
358
0
                size_t i_data = p_dr->i_length;
359
0
                uint8_t i_ratings_count = p_dr->p_data[0] & 0x3F;
360
0
                p_data++; i_data--;
361
0
                for( ; i_ratings_count && i_data > 3; i_ratings_count-- )
362
0
                {
363
0
                    uint8_t i_rated_dimensions = p_data[1];
364
0
                    if( (size_t) i_rated_dimensions * 2 + 3 > i_data ) /* one more sanity check */
365
0
                        break;
366
367
0
                    uint8_t desclen = p_data[(size_t) 2 + 2 * i_rated_dimensions];
368
0
                    p_data += (size_t) 3 + 2 * i_rated_dimensions;
369
0
                    i_data -= (size_t) 3 + 2 * i_rated_dimensions;
370
0
                    if( desclen > i_data )
371
0
                        break;
372
373
0
                    if( unlikely(psz_shortdesc_text) )
374
0
                        free( psz_shortdesc_text );
375
0
                    psz_shortdesc_text = atsc_a65_Decode_multiple_string( p_basectx->p_a65, p_data, desclen );
376
0
                    if( psz_shortdesc_text ) /* Only keep first for now */
377
0
                        break;
378
0
                    p_data += desclen;
379
0
                    i_data -= desclen;
380
0
                }
381
0
            }
382
0
            default:
383
0
                break;
384
0
        }
385
0
    }
386
387
    /* Try to match ETT */
388
0
    if( p_ett )
389
0
    {
390
0
        psz_longdesc_text = atsc_a65_Decode_multiple_string( p_basectx->p_a65,
391
0
                                                             p_ett->p_etm_data, p_ett->i_etm_length );
392
0
    }
393
394
0
    if( i_start != VLC_TICK_INVALID && psz_title )
395
0
    {
396
#ifdef ATSC_DEBUG_EIT
397
        msg_Dbg( p_demux, "EIT Event time %ld +%d %s id 0x%x",
398
                 i_start, p_evt->i_length_seconds, psz_title, p_evt->i_event_id );
399
#endif
400
0
        p_epgevt = vlc_epg_event_New( p_evt->i_event_id, i_start, p_evt->i_length_seconds );
401
0
        if( p_epgevt )
402
0
        {
403
0
            p_epgevt->psz_name = grab_notempty( &psz_title );
404
0
            p_epgevt->psz_short_description = grab_notempty( &psz_shortdesc_text );
405
0
            p_epgevt->psz_description = grab_notempty( &psz_longdesc_text );
406
0
        }
407
0
    }
408
409
0
    free( psz_title );
410
0
    free( psz_shortdesc_text );
411
0
    free( psz_longdesc_text );
412
0
    return p_epgevt;
413
0
}
414
415
static time_t ATSC_AddVLCEPGEvent( demux_t *p_demux, ts_psip_context_t *p_basectx,
416
                                   const dvbpsi_atsc_eit_event_t *p_event,
417
                                   const dvbpsi_atsc_ett_t *p_ett,
418
                                   vlc_epg_t *p_epg )
419
0
{
420
0
    vlc_epg_event_t *p_evt = ATSC_CreateVLCEPGEvent( p_demux, p_basectx,
421
0
                                                     p_event, p_ett );
422
0
    if( p_evt )
423
0
    {
424
0
        if( vlc_epg_AddEvent( p_epg, p_evt ) )
425
0
            return p_evt->i_start;
426
0
        vlc_epg_event_Delete( p_evt );
427
0
    }
428
0
    return VLC_TICK_INVALID;
429
0
}
430
431
432
static void ATSC_EIT_Callback( void *p_pid, dvbpsi_atsc_eit_t* p_eit )
433
0
{
434
0
    ts_pid_t *p_eit_pid = (ts_pid_t *) p_pid;
435
0
    if( unlikely(p_eit_pid->type != TYPE_PSIP) )
436
0
    {
437
0
        assert( p_eit_pid->type == TYPE_PSIP );
438
0
        dvbpsi_atsc_DeleteEIT( p_eit );
439
0
        return;
440
0
    }
441
442
0
    demux_t *p_demux = (demux_t *) p_eit_pid->u.p_psip->p_ctx->p_handle->p_sys;
443
0
    demux_sys_t *p_sys = p_demux->p_sys;
444
0
    ts_pid_t *p_base_pid = GetPID(p_sys, ATSC_BASE_PID);
445
0
    ts_psip_t *p_basepsip = p_base_pid->u.p_psip;
446
0
    ts_psip_context_t *p_basectx = p_basepsip->p_ctx;
447
448
0
    if( !p_eit->b_current_next ||
449
0
        unlikely(p_base_pid->type != TYPE_PSIP || !p_basectx->p_stt || !p_basectx->p_vct) )
450
0
    {
451
0
        dvbpsi_atsc_DeleteEIT( p_eit );
452
0
        return;
453
0
    }
454
455
0
    uint16_t i_program_number;
456
0
    if ( !ATSC_TranslateVChannelToProgram( p_basectx->p_vct, p_eit->i_source_id, &i_program_number ) )
457
0
    {
458
0
        msg_Warn( p_demux, "Received EIT for unknown channel %d", p_eit->i_source_id );
459
0
        dvbpsi_atsc_DeleteEIT( p_eit );
460
0
        return;
461
0
    }
462
463
0
    const ts_pid_t *pid_sibling_ett = ATSC_GetSiblingxTTPID( &p_sys->pids, p_basectx->p_mgt,
464
0
                                                     p_eit_pid->u.p_psip );
465
466
    /* Get System Time for finding and setting current event */
467
0
    time_t i_current_time = atsc_a65_GPSTimeToEpoch( p_basectx->p_stt->i_system_time,
468
0
                                                     p_basectx->p_stt->i_gps_utc_offset );
469
0
    EIT_DEBUG_TIMESHIFT( i_current_time );
470
471
0
    const uint16_t i_table_type = p_eit_pid->u.p_psip->p_ctx->i_tabletype;
472
0
    assert(i_table_type);
473
474
    /* Use PID for segmenting our EPG tables updates. 1 EIT/PID transmits 3 hours,
475
     * with a max of 16 days over 128 EIT/PID. Unlike DVD, table ID is here fixed.
476
     * see ATSC A/65 5.0 */
477
0
    vlc_epg_t *p_epg = vlc_epg_New( i_table_type - ATSC_TABLE_TYPE_EIT_0,
478
0
                                    i_program_number );
479
0
    if( !p_epg )
480
0
    {
481
0
        dvbpsi_atsc_DeleteEIT( p_eit );
482
0
        return;
483
0
    }
484
485
    /* Use first table as present/following (not split like DVB) */
486
0
    p_epg->b_present = (i_table_type == ATSC_TABLE_TYPE_EIT_0);
487
488
0
    if( !p_basectx->p_a65 && !(p_basectx->p_a65 = atsc_a65_handle_New( NULL )) )
489
0
        goto end;
490
491
0
    time_t i_current_event_start_time = 0;
492
0
    for( const dvbpsi_atsc_eit_event_t *p_evt = p_eit->p_first_event;
493
0
                                        p_evt ; p_evt = p_evt->p_next )
494
0
    {
495
        /* Try to match ETT */
496
0
        const dvbpsi_atsc_ett_t *p_ett = NULL;
497
0
        if( pid_sibling_ett )
498
0
            p_ett = ATSC_ETTFindByETMId( pid_sibling_ett->u.p_psip->p_ctx,
499
0
                                         toETMId( p_eit->i_source_id, p_evt->i_event_id ),
500
0
                                         p_eit->i_version );
501
502
        /* Add Event to EPG based on EIT / available ETT */
503
0
        time_t i_start = ATSC_AddVLCEPGEvent( p_demux, p_basectx, p_evt, p_ett, p_epg );
504
505
        /* Try to find current event */
506
0
        if( i_start <= i_current_time && i_start + p_evt->i_length_seconds > i_current_time )
507
0
            i_current_event_start_time = i_start;
508
0
    }
509
510
    /* Update epg current time from system time ( required for pruning ) */
511
0
    if( p_epg->b_present && i_current_event_start_time )
512
0
    {
513
0
        vlc_epg_SetCurrent( p_epg, i_current_event_start_time );
514
0
        ts_pat_t *p_pat = ts_pid_Get(&p_sys->pids, 0)->u.p_pat;
515
0
        ts_pmt_t *p_pmt = ts_pat_Get_pmt(p_pat, i_program_number);
516
0
        if(p_pmt)
517
0
        {
518
0
            p_pmt->eit.i_event_start = p_epg->p_current->i_start;
519
0
            p_pmt->eit.i_event_length = p_epg->p_current->i_duration;
520
0
        }
521
0
    }
522
523
0
    if( p_epg->i_event > 0 )
524
0
        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG, (int)i_program_number, p_epg );
525
526
0
end:
527
0
    vlc_epg_Delete( p_epg );
528
0
    ATSC_EITInsert( p_eit_pid->u.p_psip->p_ctx, p_eit );
529
0
}
530
531
static void ATSC_ETT_Callback( void *p_pid, dvbpsi_atsc_ett_t *p_ett )
532
0
{
533
0
    ts_pid_t *p_ett_pid = (ts_pid_t *) p_pid;
534
0
    if( unlikely(p_ett_pid->type != TYPE_PSIP) )
535
0
    {
536
0
        assert( p_ett_pid->type == TYPE_PSIP );
537
0
        dvbpsi_atsc_DeleteETT( p_ett );
538
0
        return;
539
0
    }
540
541
0
    demux_t *p_demux = (demux_t *) p_ett_pid->u.p_psip->p_ctx->p_handle->p_sys;
542
0
    demux_sys_t *p_sys = p_demux->p_sys;
543
0
    ts_pid_t *p_base_pid = GetPID(p_sys, ATSC_BASE_PID);
544
0
    ts_psip_t *p_basepsip = p_base_pid->u.p_psip;
545
0
    ts_psip_context_t *p_basectx = p_basepsip->p_ctx;
546
547
0
    if( p_ett->i_etm_id & 0x02 ) /* Event ETT */
548
0
    {
549
0
        ts_psip_context_t *p_ctx = p_ett_pid->u.p_psip->p_ctx;
550
0
        uint16_t i_vchannel_id, i_event_id;
551
0
        fromETMId( p_ett->i_etm_id, &i_vchannel_id, &i_event_id );
552
553
0
        uint16_t i_program_number;
554
0
        if ( !ATSC_TranslateVChannelToProgram( p_basectx->p_vct, i_vchannel_id, &i_program_number ) )
555
0
        {
556
0
            msg_Warn( p_demux, "Received EIT for unknown channel %d", i_vchannel_id );
557
0
            dvbpsi_atsc_DeleteETT( p_ett );
558
0
            return;
559
0
        }
560
561
        /* If ETT with that version isn't already in list (inserted when matched eit is present) */
562
0
        if( ATSC_ETTFindByETMId( p_ctx, p_ett->i_etm_id, p_ett->i_version ) == NULL )
563
0
        {
564
0
            const dvbpsi_atsc_mgt_t *p_mgt = ts_pid_Get( &p_sys->pids, ATSC_BASE_PID )->u.p_psip->p_ctx->p_mgt;
565
0
            ts_pid_t *p_sibling_eit = ATSC_GetSiblingxTTPID( &p_sys->pids, p_mgt, p_ett_pid->u.p_psip );
566
0
            if( p_sibling_eit )
567
0
            {
568
0
                const dvbpsi_atsc_eit_event_t *p_event =
569
0
                        ATSC_EventFindByETMId( p_sibling_eit->u.p_psip->p_ctx, p_ett->i_etm_id, p_ett->i_version );
570
0
                if( p_event )
571
0
                {
572
#ifdef ATSC_DEBUG_EIT
573
                    msg_Dbg( p_demux, "Should update EIT %x (matched EIT)", p_event->i_event_id );
574
#endif
575
0
                    vlc_epg_event_t *p_evt = ATSC_CreateVLCEPGEvent( p_demux, p_basectx, p_event, p_ett );
576
0
                    if( likely(p_evt) )
577
0
                    {
578
0
                        es_out_Control( p_demux->out, ES_OUT_SET_GROUP_EPG_EVENT,
579
0
                                        (int)i_program_number, p_evt );
580
#ifdef ATSC_DEBUG_EIT
581
                        msg_Dbg( p_demux, "Updated event %x with ETT", p_evt->i_id );
582
#endif
583
0
                        vlc_epg_event_Delete( p_evt );
584
0
                    }
585
0
                }
586
                /* Insert to avoid duplicated event, and to be available to EIT if didn't appear yet */
587
0
                ATSC_InsertETTOrdered( p_ctx, p_ett );
588
0
                ATSC_CleanETTByChannelVersion( p_ctx, i_vchannel_id, p_ett->i_version );
589
0
                return;
590
0
            }
591
0
        }
592
0
    }
593
0
    dvbpsi_atsc_DeleteETT( p_ett );
594
0
}
595
596
static void ATSC_ETT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section,
597
                                  void *p_base_pid )
598
0
{
599
0
    VLC_UNUSED( p_handle );
600
0
    for( ; p_section; p_section = p_section->p_next )
601
0
    {
602
0
        dvbpsi_atsc_ett_t *p_ett = DVBPlague_ETT_Decode( p_section );
603
0
        if( p_ett ) /* Send to real callback */
604
0
            ATSC_ETT_Callback( p_base_pid, p_ett );
605
0
    }
606
0
}
607
608
static void ATSC_VCT_Callback( void *p_cb_basepid, dvbpsi_atsc_vct_t* p_vct )
609
0
{
610
0
    ts_pid_t *p_base_pid = (ts_pid_t *) p_cb_basepid;
611
0
    if( unlikely(p_base_pid->type != TYPE_PSIP || p_base_pid->i_pid != ATSC_BASE_PID) )
612
0
    {
613
0
        assert( p_base_pid->type == TYPE_PSIP );
614
0
        assert( p_base_pid->i_pid == ATSC_BASE_PID );
615
0
        dvbpsi_atsc_DeleteVCT( p_vct );
616
0
        return;
617
0
    }
618
0
    demux_t *p_demux = (demux_t *) p_base_pid->u.p_psip->p_ctx->p_handle->p_sys;
619
0
    ts_psip_context_t *p_ctx = p_base_pid->u.p_psip->p_ctx;
620
621
0
    if( !p_ctx->p_a65 && !(p_ctx->p_a65 = atsc_a65_handle_New( NULL )) )
622
0
        goto end;
623
624
0
    for( const dvbpsi_atsc_vct_channel_t *p_channel = p_vct->p_first_channel;
625
0
                                          p_channel; p_channel = p_channel->p_next )
626
0
    {
627
0
        vlc_meta_t *p_meta = vlc_meta_New();
628
0
        if( p_meta )
629
0
        {
630
0
            char *psz_name = NULL;
631
632
0
            for( dvbpsi_descriptor_t *p_dr = p_channel->p_first_descriptor;
633
0
                 p_dr; p_dr = p_dr->p_next )
634
0
            {
635
0
                switch( p_dr->i_tag )
636
0
                {
637
0
                    case ATSC_DESCRIPTOR_EXTENDED_CHANNEL_NAME:
638
0
                    {
639
0
                        dvbpsi_extended_channel_name_dr_t *p_ecndr =
640
0
                                                    dvbpsi_ExtendedChannelNameDr( p_dr );
641
0
                        if( p_ecndr )
642
0
                        {
643
0
                            if( unlikely(psz_name) )
644
0
                                free( psz_name );
645
0
                            psz_name = atsc_a65_Decode_multiple_string( p_ctx->p_a65,
646
0
                                                                        p_ecndr->i_long_channel_name,
647
0
                                                                        p_ecndr->i_long_channel_name_length );
648
0
                        }
649
650
0
                    } break;
651
652
0
                    default:
653
0
                        break;
654
0
                }
655
0
            }
656
657
0
            if( !psz_name )
658
0
                psz_name = atsc_a65_Decode_simple_UTF16_string( p_ctx->p_a65,
659
0
                                                                p_channel->i_short_name, 14 );
660
0
            if( psz_name )
661
0
            {
662
0
                vlc_meta_SetTitle( p_meta, psz_name );
663
0
                free( psz_name );
664
0
            }
665
666
0
            const char *psz_service_type = ATSC_A53_get_service_type( p_channel->i_service_type );
667
0
            if( psz_service_type )
668
0
                vlc_meta_SetExtra( p_meta, "Type", psz_service_type );
669
670
0
            es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META,
671
0
                            p_channel->i_program_number, p_meta );
672
673
0
            vlc_meta_Delete( p_meta );
674
0
        }
675
0
    }
676
677
0
end:
678
0
    if( p_ctx->p_vct )
679
0
        dvbpsi_atsc_DeleteVCT( p_ctx->p_vct );
680
0
    p_ctx->p_vct = p_vct;
681
0
}
682
683
static void ATSC_MGT_Callback( void *p_cb_basepid, dvbpsi_atsc_mgt_t* p_mgt )
684
0
{
685
0
    ts_pid_t *p_base_pid = (ts_pid_t *) p_cb_basepid;
686
0
    if( unlikely(p_base_pid->type != TYPE_PSIP || p_base_pid->i_pid != ATSC_BASE_PID) )
687
0
    {
688
0
        assert( p_base_pid->type == TYPE_PSIP );
689
0
        assert( p_base_pid->i_pid == ATSC_BASE_PID );
690
0
        dvbpsi_atsc_DeleteMGT( p_mgt );
691
0
        return;
692
0
    }
693
0
    ts_psip_t *p_mgtpsip = p_base_pid->u.p_psip;
694
0
    demux_t *p_demux = (demux_t *) p_mgtpsip->p_ctx->p_handle->p_sys;
695
0
    demux_sys_t *p_sys = p_demux->p_sys;
696
697
0
    if( ( p_mgtpsip->p_ctx->i_version != -1 && p_mgtpsip->p_ctx->i_version == p_mgt->i_version ) ||
698
0
          p_mgt->b_current_next == 0 )
699
0
    {
700
0
        dvbpsi_atsc_DeleteMGT( p_mgt );
701
0
        return;
702
0
    }
703
704
    /* Easy way, delete and recreate every child if any new version comes
705
     * (We don't need to keep PID active as with video/PMT update) */
706
0
    if( p_mgtpsip->p_ctx->i_version != -1 )
707
0
    {
708
0
        if( p_mgtpsip->p_ctx->p_vct )
709
0
        {
710
0
            dvbpsi_atsc_DeleteVCT( p_mgtpsip->p_ctx->p_vct );
711
0
            p_mgtpsip->p_ctx->p_vct = NULL;
712
0
        }
713
714
        /* Remove EIT/ETT */
715
0
        for( int i=0; i < p_mgtpsip->eit.i_size; i++ )
716
0
        {
717
0
             PIDRelease( p_demux, p_mgtpsip->eit.p_elems[i] );
718
0
             assert( p_mgtpsip->eit.p_elems[i]->type == TYPE_FREE );
719
0
        }
720
0
        ARRAY_RESET(p_mgtpsip->eit);
721
722
        /* Remove EAS */
723
0
        dvbpsi_demux_t *p_dvbpsi_demux = (dvbpsi_demux_t *) p_mgtpsip->p_ctx->p_handle->p_decoder;
724
0
        dvbpsi_demux_subdec_t *p_subdec = dvbpsi_demuxGetSubDec( p_dvbpsi_demux, SCTE18_TABLE_ID, 0x00 );
725
0
        if( p_subdec )
726
0
        {
727
0
            dvbpsi_DetachDemuxSubDecoder( p_dvbpsi_demux, p_subdec );
728
0
            dvbpsi_DeleteDemuxSubDecoder( p_subdec );
729
0
        }
730
0
    }
731
732
0
    if( p_mgtpsip->p_ctx->p_mgt )
733
0
        dvbpsi_atsc_DeleteMGT( p_mgtpsip->p_ctx->p_mgt );
734
0
    p_mgtpsip->p_ctx->p_mgt = p_mgt;
735
0
    p_mgtpsip->p_ctx->i_version = p_mgt->i_version;
736
737
0
    for( const dvbpsi_atsc_mgt_table_t *p_tab = p_mgt->p_first_table;
738
0
                                        p_tab; p_tab = p_tab->p_next )
739
0
    {
740
0
        if( p_tab->i_table_type == ATSC_TABLE_TYPE_TVCT ||
741
0
            p_tab->i_table_type == ATSC_TABLE_TYPE_CVCT )
742
0
        {
743
0
            const uint8_t i_table_id = (p_tab->i_table_type == ATSC_TABLE_TYPE_CVCT)
744
0
                                     ? ATSC_CVCT_TABLE_ID
745
0
                                     : ATSC_TVCT_TABLE_ID;
746
0
            if( !ATSC_ATTACH( p_mgtpsip->p_ctx->p_handle, VCT, i_table_id,
747
0
                              GetPID(p_sys, 0)->u.p_pat->i_ts_id, p_base_pid ) )
748
0
                msg_Dbg( p_demux, "  * pid=%d listening for ATSC VCT", p_base_pid->i_pid );
749
0
        }
750
0
        else if( p_tab->i_table_type >= ATSC_TABLE_TYPE_EIT_0 &&
751
0
                 p_tab->i_table_type <= ATSC_TABLE_TYPE_EIT_0 + ATSC_EIT_MAX_DEPTH_MIN1 &&
752
0
                 p_tab->i_table_type <= ATSC_TABLE_TYPE_EIT_127 &&
753
0
                 p_tab->i_table_type_pid != p_base_pid->i_pid )
754
0
        {
755
0
            ts_pid_t *pid = GetPID(p_sys, p_tab->i_table_type_pid);
756
0
            if( PIDSetup( p_demux, TYPE_PSIP, pid, NULL ) )
757
0
            {
758
0
                SetPIDFilter( p_demux->p_sys, pid, true );
759
0
                pid->u.p_psip->p_ctx->i_tabletype = p_tab->i_table_type;
760
0
                ATSC_Ready_SubDecoders( pid->u.p_psip->p_ctx->p_handle, pid );
761
0
                msg_Dbg( p_demux, "  * pid=%d reserved for ATSC EIT", pid->i_pid );
762
0
                ARRAY_APPEND( p_mgtpsip->eit, pid );
763
0
            }
764
0
        }
765
0
        else if( p_tab->i_table_type >= ATSC_TABLE_TYPE_ETT_0 &&
766
0
                 p_tab->i_table_type <= ATSC_TABLE_TYPE_ETT_0 + ATSC_EIT_MAX_DEPTH_MIN1 &&
767
0
                 p_tab->i_table_type <= ATSC_TABLE_TYPE_ETT_127 &&
768
0
                 p_tab->i_table_type_pid != p_base_pid->i_pid )
769
0
        {
770
0
            ts_pid_t *pid = GetPID(p_sys, p_tab->i_table_type_pid);
771
0
            if( PIDSetup( p_demux, TYPE_PSIP, pid, NULL ) )
772
0
            {
773
0
                SetPIDFilter( p_sys, pid, true );
774
0
                pid->u.p_psip->p_ctx->i_tabletype = p_tab->i_table_type;
775
0
                ATSC_Ready_SubDecoders( pid->u.p_psip->p_ctx->p_handle, pid );
776
0
                msg_Dbg( p_demux, "  * pid=%d reserved for ATSC ETT", pid->i_pid );
777
0
                ARRAY_APPEND( p_mgtpsip->eit, pid );
778
0
            }
779
0
        }
780
0
        msg_Dbg( p_demux, "  * pid=%d transport for ATSC PSIP type %x",
781
0
                          p_tab->i_table_type_pid, p_tab->i_table_type );
782
0
    }
783
784
0
    if( SCTE18_SI_BASE_PID == ATSC_BASE_PID &&
785
0
        ts_dvbpsi_AttachRawSubDecoder( p_mgtpsip->p_ctx->p_handle, SCTE18_TABLE_ID, 0x00,
786
0
                                       SCTE18_Section_Callback, p_base_pid ) )
787
0
    {
788
0
        msg_Dbg( p_demux, "  * pid=%d listening for EAS", p_base_pid->i_pid );
789
0
    }
790
0
}
791
792
static void ATSC_STT_Callback( void *p_cb_basepid, dvbpsi_atsc_stt_t* p_stt )
793
0
{
794
0
    ts_pid_t *p_base_pid = (ts_pid_t *) p_cb_basepid;
795
0
    if( unlikely(p_base_pid->type != TYPE_PSIP || p_base_pid->i_pid != ATSC_BASE_PID) )
796
0
    {
797
0
        assert( p_base_pid->type == TYPE_PSIP );
798
0
        assert( p_base_pid->i_pid == ATSC_BASE_PID );
799
0
        dvbpsi_atsc_DeleteSTT( p_stt );
800
0
        return;
801
0
    }
802
0
    demux_t *p_demux = (demux_t *) p_base_pid->u.p_psip->p_ctx->p_handle->p_sys;
803
0
    demux_sys_t *p_sys = p_demux->p_sys;
804
0
    ts_psip_context_t *p_ctx = p_base_pid->u.p_psip->p_ctx;
805
0
    dvbpsi_t *p_handle = p_base_pid->u.p_psip->p_ctx->p_handle;
806
807
0
    if( !p_ctx->p_stt ) /* First call */
808
0
    {
809
0
        if( !ATSC_ATTACH( p_handle, MGT, ATSC_MGT_TABLE_ID, 0x00, p_base_pid ) )
810
0
        {
811
0
            msg_Err( p_demux, "Can't attach MGT decoder to pid %d", ATSC_BASE_PID );
812
0
            ATSC_Detach_Dvbpsi_Decoders( p_handle );
813
0
            dvbpsi_atsc_DeleteSTT( p_ctx->p_stt );
814
0
            p_stt = NULL;
815
0
        }
816
0
    }
817
0
    else
818
0
    {
819
0
        dvbpsi_atsc_DeleteSTT( p_ctx->p_stt );
820
0
    }
821
822
0
    if( p_stt )
823
0
    {
824
0
        time_t i_current_time = atsc_a65_GPSTimeToEpoch( p_stt->i_system_time,
825
0
                                                         p_stt->i_gps_utc_offset );
826
0
        EIT_DEBUG_TIMESHIFT( i_current_time );
827
0
        p_sys->i_network_time =  i_current_time;
828
0
        p_sys->i_network_time_update = time(NULL);
829
830
0
        es_out_Control( p_demux->out, ES_OUT_SET_EPG_TIME, p_sys->i_network_time );
831
0
    }
832
833
0
    p_ctx->p_stt = p_stt;
834
0
}
835
836
static void ATSC_STT_RawCallback( dvbpsi_t *p_handle, const dvbpsi_psi_section_t* p_section,
837
                                  void *p_base_pid )
838
0
{
839
0
    VLC_UNUSED( p_handle );
840
0
    for( ; p_section ; p_section = p_section->p_next )
841
0
    {
842
0
        dvbpsi_atsc_stt_t *p_stt = DVBPlague_STT_Decode( p_section );
843
0
        if( p_stt ) /* Send to real callback */
844
0
            ATSC_STT_Callback( p_base_pid, p_stt );
845
0
    }
846
0
}
847
848
bool ATSC_Attach_Dvbpsi_Base_Decoders( ts_psip_context_t *p_ctx, void *p_base_pid )
849
261
{
850
261
    if( !ATSC_ATTACH_WITH_FIXED_DECODER( p_ctx->p_handle, STT, ATSC_STT_TABLE_ID, 0x00, p_base_pid ) )
851
0
    {
852
0
        ATSC_Detach_Dvbpsi_Decoders( p_ctx->p_handle ); /* shouldn't be any, except demux */
853
0
        return false;
854
0
    }
855
261
    return true;
856
261
}
857
858
static void ATSC_NewTable_Callback( dvbpsi_t *p_dvbpsi, uint8_t i_table_id,
859
                                    uint16_t i_extension, void *p_cb_pid )
860
0
{
861
0
    demux_t *p_demux = (demux_t *) p_dvbpsi->p_sys;
862
0
    demux_sys_t *p_sys = p_demux->p_sys;
863
0
    assert( ((ts_pid_t *) p_cb_pid)->type == TYPE_PSIP );
864
0
    const ts_pid_t *p_base_pid = ts_pid_Get( &p_sys->pids, ATSC_BASE_PID );
865
0
    if( !p_base_pid->u.p_psip->p_ctx->p_vct )
866
0
        return;
867
868
0
    switch( i_table_id )
869
0
    {
870
0
        case ATSC_ETT_TABLE_ID:
871
0
            if( !ATSC_ATTACH_WITH_FIXED_DECODER( p_dvbpsi, ETT, ATSC_ETT_TABLE_ID, i_extension, p_cb_pid ) )
872
0
                msg_Warn( p_demux, "Cannot attach ETT decoder source %" PRIu16, i_extension );
873
0
            break;
874
875
0
        case ATSC_EIT_TABLE_ID:
876
0
            if( !ATSC_ATTACH( p_dvbpsi, EIT, ATSC_EIT_TABLE_ID, i_extension, p_cb_pid ) )
877
0
                msg_Warn( p_demux, "Cannot attach EIT decoder source %" PRIu16, i_extension );
878
0
            break;
879
880
0
        default:
881
0
            break;
882
0
    }
883
0
}