Coverage Report

Created: 2026-07-12 08:57

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
17.1k
{
43
17.1k
    ts_pat_t *pat = malloc( sizeof( ts_pat_t ) );
44
17.1k
    if( !pat )
45
0
        return NULL;
46
47
17.1k
    pat->p_ctx = ts_psi_context_New( p_demux );
48
17.1k
    if( !pat->p_ctx )
49
0
    {
50
0
        free( pat );
51
0
        return NULL;
52
0
    }
53
54
17.1k
    pat->i_version  = -1;
55
17.1k
    pat->i_ts_id    = -1;
56
17.1k
    pat->b_generated = false;
57
17.1k
    ARRAY_INIT( pat->programs );
58
59
17.1k
    return pat;
60
17.1k
}
61
62
void ts_pat_Del( demux_t *p_demux, ts_pat_t *pat )
63
17.1k
{
64
17.1k
    ts_psi_context_Delete( pat->p_ctx );
65
35.8k
    for( int i=0; i<pat->programs.i_size; i++ )
66
18.7k
        PIDRelease( p_demux, pat->programs.p_elems[i] );
67
17.1k
    ARRAY_RESET( pat->programs );
68
17.1k
    free( pat );
69
17.1k
}
70
71
ts_pmt_t *ts_pat_Get_pmt( ts_pat_t *pat, uint16_t i_number )
72
656
{
73
656
    ts_pmt_t *p_pmt = NULL;
74
1.75k
    for( int i=0; i<pat->programs.i_size; i++ )
75
1.55k
    {
76
1.55k
        p_pmt = pat->programs.p_elems[i]->u.p_pmt;
77
1.55k
        if( p_pmt->i_number == i_number )
78
455
            break;
79
1.55k
    }
80
656
    return p_pmt;
81
656
}
82
83
ts_pmt_t *ts_pmt_New( demux_t *p_demux )
84
18.8k
{
85
18.8k
    ts_pmt_t *pmt = malloc( sizeof( ts_pmt_t ) );
86
18.8k
    if( !pmt )
87
0
        return NULL;
88
89
18.8k
    pmt->p_ctx = ts_psi_context_New( p_demux );
90
18.8k
    if( !pmt->p_ctx )
91
0
    {
92
0
        free( pmt );
93
0
        return NULL;
94
0
    }
95
96
18.8k
    ARRAY_INIT( pmt->e_streams );
97
98
    //pmt->pmtcache   = NULL;
99
18.8k
    pmt->i_version  = -1;
100
18.8k
    pmt->i_number   = -1;
101
18.8k
    pmt->i_pid_pcr  = 0x1FFF;
102
18.8k
    pmt->b_selected = false;
103
18.8k
    pmt->iod        = NULL;
104
18.8k
    pmt->od.i_version = -1;
105
18.8k
    ARRAY_INIT( pmt->od.objects );
106
107
18.8k
    pmt->i_last_dts = VLC_TICK_INVALID;
108
18.8k
    pmt->i_last_dts_byte = 0;
109
18.8k
    pmt->b_last_dts_probed = false;
110
111
18.8k
    pmt->p_atsc_si_basepid      = NULL;
112
18.8k
    pmt->p_si_sdt_pid = NULL;
113
114
18.8k
    pmt->pcr.i_current = VLC_TICK_INVALID;
115
18.8k
    pmt->pcr.i_first  = VLC_TICK_INVALID;
116
18.8k
    pmt->pcr.b_disable = false;
117
18.8k
    pmt->pcr.i_first_dts = VLC_TICK_INVALID;
118
18.8k
    pmt->pcr.i_pcroffset = -1;
119
120
18.8k
    pmt->pcr.b_fix_done = false;
121
122
18.8k
    pmt->eit.i_event_length = 0;
123
18.8k
    pmt->eit.i_event_start = 0;
124
125
18.8k
    pmt->arib.i_download_id = -1;
126
18.8k
    pmt->arib.i_logo_id = -1;
127
128
18.8k
    return pmt;
129
18.8k
}
130
131
void ts_pmt_Del( demux_t *p_demux, ts_pmt_t *pmt )
132
18.8k
{
133
18.8k
    ts_psi_context_Delete( pmt->p_ctx );
134
77.9k
    for( int i=0; i<pmt->e_streams.i_size; i++ )
135
59.0k
        PIDRelease( p_demux, pmt->e_streams.p_elems[i] );
136
18.8k
    ARRAY_RESET( pmt->e_streams );
137
18.8k
    if( pmt->p_atsc_si_basepid )
138
221
        PIDRelease( p_demux, pmt->p_atsc_si_basepid );
139
18.8k
    if( pmt->p_si_sdt_pid )
140
16.3k
        PIDRelease( p_demux, pmt->p_si_sdt_pid );
141
18.8k
    if( pmt->iod )
142
12.8k
        ODFree( pmt->iod );
143
43.1k
    for( int i=0; i<pmt->od.objects.i_size; i++ )
144
24.2k
        ODFree( pmt->od.objects.p_elems[i] );
145
18.8k
    ARRAY_RESET( pmt->od.objects );
146
18.8k
    if( pmt->i_number > -1 )
147
18.8k
        es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, pmt->i_number );
148
149
18.8k
    free( pmt );
150
18.8k
}
151
152
ts_es_t * ts_es_New( ts_pmt_t *p_program )
153
128k
{
154
128k
    ts_es_t *p_es = malloc( sizeof(*p_es) );
155
128k
    if( p_es )
156
128k
    {
157
128k
        p_es->p_program = p_program;
158
128k
        p_es->id = NULL;
159
128k
        p_es->i_sl_es_id = 0;
160
128k
        p_es->i_next_block_flags = 0;
161
128k
        p_es->p_extraes = NULL;
162
128k
        p_es->p_next = NULL;
163
128k
        p_es->b_interlaced = false;
164
128k
        es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
165
128k
        p_es->fmt.i_group = p_program->i_number;
166
128k
        p_es->metadata.i_application_format_identifier = 0;
167
128k
        p_es->metadata.i_format_identifier = 0;
168
128k
        p_es->metadata.i_service_id = 0;
169
128k
    }
170
128k
    return p_es;
171
128k
}
172
173
static void ts_pes_es_Clean( demux_t *p_demux, ts_es_t *p_es )
174
128k
{
175
128k
    demux_sys_t *p_sys = p_demux->p_sys;
176
177
128k
    if( p_es->id )
178
53.8k
    {
179
        /* Ensure we don't wait for overlap hacks #14257 */
180
53.8k
        es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, p_es->id, false );
181
53.8k
        es_out_Del( p_demux->out, p_es->id );
182
53.8k
        p_sys->i_pmt_es--;
183
53.8k
    }
184
128k
    es_format_Clean( &p_es->fmt );
185
128k
}
186
187
void ts_stream_Add_es( ts_stream_t *p_pes, ts_es_t *p_es, bool b_extra )
188
24
{
189
24
    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
24
                           &p_pes->p_es;
192
24
    if( likely(!*pp_es) )
193
24
    {
194
24
        *pp_es = p_es;
195
24
    }
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
24
}
203
204
ts_es_t * ts_stream_Find_es( ts_stream_t *p_pes, const ts_pmt_t *p_pmt )
205
12
{
206
12
    for( ts_es_t *p_es = p_pes->p_es; p_es; p_es = p_es->p_next )
207
12
    {
208
12
        if( p_es->p_program == p_pmt )
209
12
            return p_es;
210
12
    }
211
0
    return NULL;
212
12
}
213
214
ts_es_t * ts_stream_Extract_es( ts_stream_t *p_pes, const ts_pmt_t *p_pmt )
215
24
{
216
24
    ts_es_t **pp_prev = &p_pes->p_es;
217
24
    for( ts_es_t *p_es = p_pes->p_es; p_es; p_es = p_es->p_next )
218
24
    {
219
24
        if( p_es->p_program == p_pmt )
220
24
        {
221
24
            *pp_prev = p_es->p_next;
222
24
            p_es->p_next = NULL;
223
24
            return p_es;
224
24
        }
225
0
        pp_prev = &p_es->p_next;
226
0
    }
227
0
    return NULL;
228
24
}
229
230
size_t ts_Count_es( const ts_es_t *p_es, bool b_active, const ts_pmt_t *p_pmt )
231
12
{
232
12
    size_t i=0;
233
12
    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
12
    return i;
239
12
}
240
241
static void ts_pes_ChainDelete_es( demux_t *p_demux, ts_es_t *p_es )
242
255k
{
243
383k
    while( p_es )
244
128k
    {
245
128k
        ts_es_t *p_next = p_es->p_next;
246
128k
        ts_pes_ChainDelete_es( p_demux, p_es->p_extraes );
247
128k
        ts_pes_es_Clean( p_demux, p_es );
248
128k
        free( p_es );
249
128k
        p_es = p_next;
250
128k
    }
251
255k
}
252
253
ts_stream_t *ts_stream_New( demux_t *p_demux, ts_pmt_t *p_program )
254
126k
{
255
126k
    VLC_UNUSED(p_demux);
256
126k
    ts_stream_t *pes = malloc( sizeof( ts_stream_t ) );
257
126k
    if( !pes )
258
0
        return NULL;
259
260
126k
    pes->p_es = ts_es_New( p_program );
261
126k
    if( !pes->p_es )
262
0
    {
263
0
        free( pes );
264
0
        return NULL;
265
0
    }
266
126k
    pes->i_stream_type = 0;
267
126k
    pes->transport = TS_TRANSPORT_PES;
268
126k
    pes->gather.i_data_size = 0;
269
126k
    pes->gather.i_gathered = 0;
270
126k
    pes->gather.p_data = NULL;
271
126k
    pes->gather.pp_last = &pes->gather.p_data;
272
126k
    pes->gather.i_saved = 0;
273
126k
    pes->gather.i_block_flags = 0;
274
126k
    pes->gather.i_append_pcr = TS_90KHZ_INVALID;
275
126k
    pes->b_broken_PUSI_conformance = false;
276
126k
    pes->b_always_receive = false;
277
126k
    pes->p_sections_proc = NULL;
278
126k
    pes->p_proc = NULL;
279
126k
    pes->prepcr.p_head = NULL;
280
126k
    pes->prepcr.pp_last = &pes->prepcr.p_head;
281
126k
    pes->i_last_dts = VLC_TICK_INVALID;
282
283
126k
    return pes;
284
126k
}
285
286
void ts_stream_Del( demux_t *p_demux, ts_stream_t *pes )
287
126k
{
288
126k
    ts_pes_ChainDelete_es( p_demux, pes->p_es );
289
290
126k
    if( pes->gather.p_data )
291
9.35k
        block_ChainRelease( pes->gather.p_data );
292
293
126k
    if( pes->p_sections_proc )
294
53.0k
        ts_sections_processor_ChainDelete( pes->p_sections_proc );
295
296
126k
    if( pes->p_proc )
297
52.7k
        ts_stream_processor_Delete( pes->p_proc );
298
299
126k
    if( pes->prepcr.p_head )
300
754
        block_ChainRelease( pes->prepcr.p_head );
301
302
126k
    free( pes );
303
126k
}
304
305
ts_si_t *ts_si_New( demux_t *p_demux )
306
16.5k
{
307
16.5k
    ts_si_t *si = malloc( sizeof( ts_si_t ) );
308
16.5k
    if( !si )
309
0
        return NULL;
310
311
16.5k
    si->p_ctx = ts_si_context_New( p_demux );
312
16.5k
    if( !si->p_ctx )
313
0
    {
314
0
        free( si );
315
0
        return NULL;
316
0
    }
317
318
16.5k
    si->eitpid = NULL;
319
16.5k
    si->tdtpid = NULL;
320
16.5k
    si->cdtpid = NULL;
321
322
16.5k
    return si;
323
16.5k
}
324
325
void ts_si_Del( demux_t *p_demux, ts_si_t *si )
326
16.5k
{
327
16.5k
    ts_si_context_Delete( si->p_ctx );
328
16.5k
    if( si->eitpid )
329
140
        PIDRelease( p_demux, si->eitpid );
330
16.5k
    if( si->tdtpid )
331
140
        PIDRelease( p_demux, si->tdtpid );
332
16.5k
    if( si->cdtpid )
333
0
        PIDRelease( p_demux, si->cdtpid );
334
16.5k
    free( si );
335
16.5k
}
336
337
void ts_psip_Del( demux_t *p_demux, ts_psip_t *psip )
338
652
{
339
652
    ts_psip_context_Delete( psip->p_ctx );
340
341
652
    ts_pes_ChainDelete_es( p_demux, psip->p_eas_es );
342
343
1.08k
    for( int i=0; i<psip->eit.i_size; i++ )
344
436
        PIDRelease( p_demux, psip->eit.p_elems[i] );
345
652
    ARRAY_RESET( psip->eit );
346
347
652
    free( psip );
348
652
}
349
350
ts_psip_t *ts_psip_New( demux_t *p_demux )
351
652
{
352
652
    ts_psip_t *psip = malloc( sizeof( ts_psip_t ) );
353
652
    if( !psip )
354
0
        return NULL;
355
356
652
    psip->p_ctx = ts_psip_context_New( p_demux );
357
652
    if( !psip->p_ctx )
358
0
    {
359
0
        free( psip );
360
0
        return NULL;
361
0
    }
362
363
652
    ARRAY_INIT( psip->eit );
364
652
    psip->p_eas_es = NULL;
365
366
652
    return psip;
367
652
}