Coverage Report

Created: 2026-03-31 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_streams.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_streams.c: Transport Stream input module for VLC.
3
 *****************************************************************************
4
 * Copyright (C) 2004-2016 VLC authors and VideoLAN
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
25
#include "ts_pid.h"
26
#include "ts_streams.h"
27
#include "ts_streams_private.h"
28
29
#include <vlc_demux.h>
30
#include <vlc_es.h>
31
#include <vlc_es_out.h>
32
33
#include "sections.h"
34
#include "ts_pid.h"
35
#include "ts.h"
36
37
#include "ts_psi.h"
38
#include "ts_si.h"
39
#include "ts_psip.h"
40
41
ts_pat_t *ts_pat_New( demux_t *p_demux )
42
11.1k
{
43
11.1k
    ts_pat_t *pat = malloc( sizeof( ts_pat_t ) );
44
11.1k
    if( !pat )
45
0
        return NULL;
46
47
11.1k
    pat->p_ctx = ts_psi_context_New( p_demux );
48
11.1k
    if( !pat->p_ctx )
49
0
    {
50
0
        free( pat );
51
0
        return NULL;
52
0
    }
53
54
11.1k
    pat->i_version  = -1;
55
11.1k
    pat->i_ts_id    = -1;
56
11.1k
    pat->b_generated = false;
57
11.1k
    ARRAY_INIT( pat->programs );
58
59
11.1k
    return pat;
60
11.1k
}
61
62
void ts_pat_Del( demux_t *p_demux, ts_pat_t *pat )
63
11.1k
{
64
11.1k
    ts_psi_context_Delete( pat->p_ctx );
65
23.9k
    for( int i=0; i<pat->programs.i_size; i++ )
66
12.7k
        PIDRelease( p_demux, pat->programs.p_elems[i] );
67
11.1k
    ARRAY_RESET( pat->programs );
68
11.1k
    free( pat );
69
11.1k
}
70
71
ts_pmt_t *ts_pat_Get_pmt( ts_pat_t *pat, uint16_t i_number )
72
441
{
73
441
    ts_pmt_t *p_pmt = NULL;
74
1.16k
    for( int i=0; i<pat->programs.i_size; i++ )
75
1.01k
    {
76
1.01k
        p_pmt = pat->programs.p_elems[i]->u.p_pmt;
77
1.01k
        if( p_pmt->i_number == i_number )
78
286
            break;
79
1.01k
    }
80
441
    return p_pmt;
81
441
}
82
83
ts_pmt_t *ts_pmt_New( demux_t *p_demux )
84
12.9k
{
85
12.9k
    ts_pmt_t *pmt = malloc( sizeof( ts_pmt_t ) );
86
12.9k
    if( !pmt )
87
0
        return NULL;
88
89
12.9k
    pmt->p_ctx = ts_psi_context_New( p_demux );
90
12.9k
    if( !pmt->p_ctx )
91
0
    {
92
0
        free( pmt );
93
0
        return NULL;
94
0
    }
95
96
12.9k
    ARRAY_INIT( pmt->e_streams );
97
98
    //pmt->pmtcache   = NULL;
99
12.9k
    pmt->i_version  = -1;
100
12.9k
    pmt->i_number   = -1;
101
12.9k
    pmt->i_pid_pcr  = 0x1FFF;
102
12.9k
    pmt->b_selected = false;
103
12.9k
    pmt->iod        = NULL;
104
12.9k
    pmt->od.i_version = -1;
105
12.9k
    ARRAY_INIT( pmt->od.objects );
106
107
12.9k
    pmt->i_last_dts = VLC_TICK_INVALID;
108
12.9k
    pmt->i_last_dts_byte = 0;
109
12.9k
    pmt->b_last_dts_probed = false;
110
111
12.9k
    pmt->p_atsc_si_basepid      = NULL;
112
12.9k
    pmt->p_si_sdt_pid = NULL;
113
114
12.9k
    pmt->pcr.i_current = VLC_TICK_INVALID;
115
12.9k
    pmt->pcr.i_first  = VLC_TICK_INVALID;
116
12.9k
    pmt->pcr.b_disable = false;
117
12.9k
    pmt->pcr.i_first_dts = VLC_TICK_INVALID;
118
12.9k
    pmt->pcr.i_pcroffset = -1;
119
120
12.9k
    pmt->pcr.b_fix_done = false;
121
122
12.9k
    pmt->eit.i_event_length = 0;
123
12.9k
    pmt->eit.i_event_start = 0;
124
125
12.9k
    pmt->arib.i_download_id = -1;
126
12.9k
    pmt->arib.i_logo_id = -1;
127
128
12.9k
    return pmt;
129
12.9k
}
130
131
void ts_pmt_Del( demux_t *p_demux, ts_pmt_t *pmt )
132
12.9k
{
133
12.9k
    ts_psi_context_Delete( pmt->p_ctx );
134
53.9k
    for( int i=0; i<pmt->e_streams.i_size; i++ )
135
40.9k
        PIDRelease( p_demux, pmt->e_streams.p_elems[i] );
136
12.9k
    ARRAY_RESET( pmt->e_streams );
137
12.9k
    if( pmt->p_atsc_si_basepid )
138
71
        PIDRelease( p_demux, pmt->p_atsc_si_basepid );
139
12.9k
    if( pmt->p_si_sdt_pid )
140
10.2k
        PIDRelease( p_demux, pmt->p_si_sdt_pid );
141
12.9k
    if( pmt->iod )
142
8.92k
        ODFree( pmt->iod );
143
27.6k
    for( int i=0; i<pmt->od.objects.i_size; i++ )
144
14.6k
        ODFree( pmt->od.objects.p_elems[i] );
145
12.9k
    ARRAY_RESET( pmt->od.objects );
146
12.9k
    if( pmt->i_number > -1 )
147
12.9k
        es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, pmt->i_number );
148
149
12.9k
    free( pmt );
150
12.9k
}
151
152
ts_es_t * ts_es_New( ts_pmt_t *p_program )
153
41.0k
{
154
41.0k
    ts_es_t *p_es = malloc( sizeof(*p_es) );
155
41.0k
    if( p_es )
156
41.0k
    {
157
41.0k
        p_es->p_program = p_program;
158
41.0k
        p_es->id = NULL;
159
41.0k
        p_es->i_sl_es_id = 0;
160
41.0k
        p_es->i_next_block_flags = 0;
161
41.0k
        p_es->p_extraes = NULL;
162
41.0k
        p_es->p_next = NULL;
163
41.0k
        p_es->b_interlaced = false;
164
41.0k
        es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
165
41.0k
        p_es->fmt.i_group = p_program->i_number;
166
41.0k
        p_es->metadata.i_application_format_identifier = 0;
167
41.0k
        p_es->metadata.i_format_identifier = 0;
168
41.0k
        p_es->metadata.i_service_id = 0;
169
41.0k
    }
170
41.0k
    return p_es;
171
41.0k
}
172
173
static void ts_pes_es_Clean( demux_t *p_demux, ts_es_t *p_es )
174
41.0k
{
175
41.0k
    demux_sys_t *p_sys = p_demux->p_sys;
176
177
41.0k
    if( p_es->id )
178
17.5k
    {
179
        /* Ensure we don't wait for overlap hacks #14257 */
180
17.5k
        es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, p_es->id, false );
181
17.5k
        es_out_Del( p_demux->out, p_es->id );
182
17.5k
        p_sys->i_pmt_es--;
183
17.5k
    }
184
41.0k
    es_format_Clean( &p_es->fmt );
185
41.0k
}
186
187
void ts_stream_Add_es( ts_stream_t *p_pes, ts_es_t *p_es, bool b_extra )
188
0
{
189
0
    ts_es_t **pp_es = (b_extra && p_pes->p_es) ?  /* Ensure extra has main es */
190
0
                           &p_pes->p_es->p_extraes :
191
0
                           &p_pes->p_es;
192
0
    if( likely(!*pp_es) )
193
0
    {
194
0
        *pp_es = p_es;
195
0
    }
196
0
    else
197
0
    {
198
0
        ts_es_t *p_next = (*pp_es)->p_next;
199
0
        (*pp_es)->p_next = p_es;
200
0
        p_es->p_next = p_next;
201
0
    }
202
0
}
203
204
ts_es_t * ts_stream_Find_es( ts_stream_t *p_pes, const ts_pmt_t *p_pmt )
205
0
{
206
0
    for( ts_es_t *p_es = p_pes->p_es; p_es; p_es = p_es->p_next )
207
0
    {
208
0
        if( p_es->p_program == p_pmt )
209
0
            return p_es;
210
0
    }
211
0
    return NULL;
212
0
}
213
214
ts_es_t * ts_stream_Extract_es( ts_stream_t *p_pes, const ts_pmt_t *p_pmt )
215
0
{
216
0
    ts_es_t **pp_prev = &p_pes->p_es;
217
0
    for( ts_es_t *p_es = p_pes->p_es; p_es; p_es = p_es->p_next )
218
0
    {
219
0
        if( p_es->p_program == p_pmt )
220
0
        {
221
0
            *pp_prev = p_es->p_next;
222
0
            p_es->p_next = NULL;
223
0
            return p_es;
224
0
        }
225
0
        pp_prev = &p_es->p_next;
226
0
    }
227
0
    return NULL;
228
0
}
229
230
size_t ts_Count_es( const ts_es_t *p_es, bool b_active, const ts_pmt_t *p_pmt )
231
0
{
232
0
    size_t i=0;
233
0
    for( ; p_es; p_es = p_es->p_next )
234
0
    {
235
0
        i += ( b_active ) ? !!p_es->id : ( ( !p_pmt || p_pmt == p_es->p_program ) ? 1 : 0 );
236
0
        i += ts_Count_es( p_es->p_extraes, b_active, p_pmt );
237
0
    }
238
0
    return i;
239
0
}
240
241
static void ts_pes_ChainDelete_es( demux_t *p_demux, ts_es_t *p_es )
242
82.1k
{
243
123k
    while( p_es )
244
41.0k
    {
245
41.0k
        ts_es_t *p_next = p_es->p_next;
246
41.0k
        ts_pes_ChainDelete_es( p_demux, p_es->p_extraes );
247
41.0k
        ts_pes_es_Clean( p_demux, p_es );
248
41.0k
        free( p_es );
249
41.0k
        p_es = p_next;
250
41.0k
    }
251
82.1k
}
252
253
ts_stream_t *ts_stream_New( demux_t *p_demux, ts_pmt_t *p_program )
254
40.9k
{
255
40.9k
    VLC_UNUSED(p_demux);
256
40.9k
    ts_stream_t *pes = malloc( sizeof( ts_stream_t ) );
257
40.9k
    if( !pes )
258
0
        return NULL;
259
260
40.9k
    pes->p_es = ts_es_New( p_program );
261
40.9k
    if( !pes->p_es )
262
0
    {
263
0
        free( pes );
264
0
        return NULL;
265
0
    }
266
40.9k
    pes->i_stream_type = 0;
267
40.9k
    pes->transport = TS_TRANSPORT_PES;
268
40.9k
    pes->gather.i_data_size = 0;
269
40.9k
    pes->gather.i_gathered = 0;
270
40.9k
    pes->gather.p_data = NULL;
271
40.9k
    pes->gather.pp_last = &pes->gather.p_data;
272
40.9k
    pes->gather.i_saved = 0;
273
40.9k
    pes->gather.i_block_flags = 0;
274
40.9k
    pes->gather.i_append_pcr = TS_90KHZ_INVALID;
275
40.9k
    pes->b_broken_PUSI_conformance = false;
276
40.9k
    pes->b_always_receive = false;
277
40.9k
    pes->p_sections_proc = NULL;
278
40.9k
    pes->p_proc = NULL;
279
40.9k
    pes->prepcr.p_head = NULL;
280
40.9k
    pes->prepcr.pp_last = &pes->prepcr.p_head;
281
40.9k
    pes->i_last_dts = VLC_TICK_INVALID;
282
283
40.9k
    return pes;
284
40.9k
}
285
286
void ts_stream_Del( demux_t *p_demux, ts_stream_t *pes )
287
40.9k
{
288
40.9k
    ts_pes_ChainDelete_es( p_demux, pes->p_es );
289
290
40.9k
    if( pes->gather.p_data )
291
5.54k
        block_ChainRelease( pes->gather.p_data );
292
293
40.9k
    if( pes->p_sections_proc )
294
17.8k
        ts_sections_processor_ChainDelete( pes->p_sections_proc );
295
296
40.9k
    if( pes->p_proc )
297
17.8k
        ts_stream_processor_Delete( pes->p_proc );
298
299
40.9k
    if( pes->prepcr.p_head )
300
395
        block_ChainRelease( pes->prepcr.p_head );
301
302
40.9k
    free( pes );
303
40.9k
}
304
305
ts_si_t *ts_si_New( demux_t *p_demux )
306
10.4k
{
307
10.4k
    ts_si_t *si = malloc( sizeof( ts_si_t ) );
308
10.4k
    if( !si )
309
0
        return NULL;
310
311
10.4k
    si->p_ctx = ts_si_context_New( p_demux );
312
10.4k
    if( !si->p_ctx )
313
0
    {
314
0
        free( si );
315
0
        return NULL;
316
0
    }
317
318
10.4k
    si->eitpid = NULL;
319
10.4k
    si->tdtpid = NULL;
320
10.4k
    si->cdtpid = NULL;
321
322
10.4k
    return si;
323
10.4k
}
324
325
void ts_si_Del( demux_t *p_demux, ts_si_t *si )
326
10.4k
{
327
10.4k
    ts_si_context_Delete( si->p_ctx );
328
10.4k
    if( si->eitpid )
329
89
        PIDRelease( p_demux, si->eitpid );
330
10.4k
    if( si->tdtpid )
331
89
        PIDRelease( p_demux, si->tdtpid );
332
10.4k
    if( si->cdtpid )
333
0
        PIDRelease( p_demux, si->cdtpid );
334
10.4k
    free( si );
335
10.4k
}
336
337
void ts_psip_Del( demux_t *p_demux, ts_psip_t *psip )
338
71
{
339
71
    ts_psip_context_Delete( psip->p_ctx );
340
341
71
    ts_pes_ChainDelete_es( p_demux, psip->p_eas_es );
342
343
71
    for( int i=0; i<psip->eit.i_size; i++ )
344
0
        PIDRelease( p_demux, psip->eit.p_elems[i] );
345
71
    ARRAY_RESET( psip->eit );
346
347
71
    free( psip );
348
71
}
349
350
ts_psip_t *ts_psip_New( demux_t *p_demux )
351
71
{
352
71
    ts_psip_t *psip = malloc( sizeof( ts_psip_t ) );
353
71
    if( !psip )
354
0
        return NULL;
355
356
71
    psip->p_ctx = ts_psip_context_New( p_demux );
357
71
    if( !psip->p_ctx )
358
0
    {
359
0
        free( psip );
360
0
        return NULL;
361
0
    }
362
363
71
    ARRAY_INIT( psip->eit );
364
71
    psip->p_eas_es = NULL;
365
366
71
    return psip;
367
71
}