Coverage Report

Created: 2026-11-12 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_pid.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_pid.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
#include <vlc_demux.h>
25
26
#include "ts_pid.h"
27
#include "ts_streams.h"
28
#include "timestamps.h"
29
30
#include "ts.h"
31
32
#include <assert.h>
33
#include <stdlib.h>
34
35
38.7k
#define PID_ALLOC_CHUNK 16
36
37
void ts_pid_list_Init( ts_pid_list_t *p_list )
38
18.6k
{
39
18.6k
    p_list->dummy.i_pid = 8191;
40
18.6k
    p_list->dummy.i_flags = FLAG_SEEN;
41
18.6k
    p_list->base_si.i_pid = 0x1FFB;
42
18.6k
    p_list->pp_all = NULL;
43
18.6k
    p_list->i_all = 0;
44
18.6k
    p_list->i_all_alloc = 0;
45
18.6k
    p_list->i_last_pid = 0;
46
18.6k
    p_list->p_last = NULL;
47
18.6k
}
48
49
void ts_pid_list_Release( demux_t *p_demux, ts_pid_list_t *p_list )
50
18.6k
{
51
154k
    for( int i = 0; i < p_list->i_all; i++ )
52
135k
    {
53
135k
        ts_pid_t *pid = p_list->pp_all[i];
54
135k
#ifndef NDEBUG
55
135k
        if( pid->type != TYPE_FREE )
56
135k
            msg_Err( p_demux, "PID %d type %d not freed refcount %d", pid->i_pid, pid->type, pid->i_refcount );
57
#else
58
        VLC_UNUSED(p_demux);
59
#endif
60
135k
        free( pid );
61
135k
    }
62
18.6k
    free( p_list->pp_all );
63
18.6k
}
64
65
struct searchkey
66
{
67
    int16_t i_pid;
68
    ts_pid_t *const *pp_last;
69
};
70
71
static int ts_bsearch_searchkey_Compare( const void *key, const void *other )
72
8.85M
{
73
8.85M
    struct searchkey *p_key = (void *)key;
74
8.85M
    ts_pid_t *const *pp_pid = other;
75
76
8.85M
    ts_pid_t *p_pid = *pp_pid;
77
8.85M
    p_key->pp_last = other;
78
8.85M
    return ( p_key->i_pid >= p_pid->i_pid ) ? p_key->i_pid - p_pid->i_pid : -1;
79
8.85M
}
80
81
ts_pid_t * ts_pid_Get( ts_pid_list_t *p_list, uint16_t i_pid )
82
11.1M
{
83
11.1M
    switch( i_pid )
84
11.1M
    {
85
4.12M
        case 0:
86
4.12M
            return &p_list->pat;
87
80.1k
        case 0x1FFB:
88
80.1k
            return &p_list->base_si;
89
450k
        case 0x1FFF:
90
450k
            return &p_list->dummy;
91
6.44M
        default:
92
6.44M
            if( p_list->i_last_pid == i_pid )
93
3.12M
                return p_list->p_last;
94
3.32M
        break;
95
11.1M
    }
96
97
3.32M
    size_t i_index = 0;
98
3.32M
    ts_pid_t *p_pid = NULL;
99
100
3.32M
    if( p_list->pp_all )
101
3.30M
    {
102
3.30M
        struct searchkey pidkey;
103
3.30M
        pidkey.i_pid = i_pid;
104
3.30M
        pidkey.pp_last = NULL;
105
106
3.30M
        ts_pid_t **pp_pidk = bsearch( &pidkey, p_list->pp_all, p_list->i_all,
107
3.30M
                                      sizeof(ts_pid_t *), ts_bsearch_searchkey_Compare );
108
3.30M
        if ( pp_pidk )
109
3.18M
            p_pid = *pp_pidk;
110
117k
        else
111
117k
            i_index = (pidkey.pp_last - p_list->pp_all); /* Last visited index */
112
3.30M
    }
113
114
3.32M
    if( p_pid == NULL )
115
135k
    {
116
135k
        if( p_list->i_all >= p_list->i_all_alloc )
117
19.3k
        {
118
19.3k
            ts_pid_t **p_realloc = realloc( p_list->pp_all,
119
19.3k
                                            (p_list->i_all_alloc + PID_ALLOC_CHUNK) * sizeof(ts_pid_t *) );
120
19.3k
            if( !p_realloc )
121
0
            {
122
0
                abort();
123
                //return NULL;
124
0
            }
125
19.3k
            p_list->pp_all = p_realloc;
126
19.3k
            p_list->i_all_alloc += PID_ALLOC_CHUNK;
127
19.3k
        }
128
129
135k
        p_pid = calloc( 1, sizeof(*p_pid) );
130
135k
        if( !p_pid )
131
0
        {
132
0
            abort();
133
            //return NULL;
134
0
        }
135
136
135k
        p_pid->i_cc  = 0xff;
137
135k
        p_pid->i_pid = i_pid;
138
139
        /* Do insertion based on last bsearch mid point */
140
135k
        if( p_list->i_all )
141
117k
        {
142
117k
            if( p_list->pp_all[i_index]->i_pid < i_pid )
143
56.3k
                i_index++;
144
145
117k
            memmove( &p_list->pp_all[i_index + 1],
146
117k
                    &p_list->pp_all[i_index],
147
117k
                    (p_list->i_all - i_index) * sizeof(ts_pid_t *) );
148
117k
        }
149
150
135k
        p_list->pp_all[i_index] = p_pid;
151
135k
        p_list->i_all++;
152
153
135k
    }
154
155
3.32M
    p_list->p_last = p_pid;
156
3.32M
    p_list->i_last_pid = i_pid;
157
158
3.32M
    return p_pid;
159
3.32M
}
160
161
ts_pid_t * ts_pid_Next( ts_pid_list_t *p_list, ts_pid_next_context_t *p_ctx )
162
3.17k
{
163
3.17k
    if( likely(p_list->i_all && p_ctx) )
164
3.17k
    {
165
3.17k
        if( p_ctx->i_pos < p_list->i_all )
166
2.80k
            return p_list->pp_all[p_ctx->i_pos++];
167
3.17k
    }
168
379
    return NULL;
169
3.17k
}
170
171
static void PIDReset( ts_pid_t *pid )
172
367k
{
173
367k
    assert(pid->i_refcount == 0);
174
367k
    pid->i_cc       = 0xff;
175
367k
    pid->i_dup      = 0;
176
367k
    pid->i_flags    &= ~FLAG_SCRAMBLED;
177
367k
    pid->type = TYPE_FREE;
178
367k
    pid->i_scramble_counter = 0;
179
367k
    memset(pid->prevpktbytes, 0, PREVPKTKEEPBYTES);
180
367k
}
181
182
bool PIDSetup( demux_t *p_demux, ts_pid_type_t i_type, ts_pid_t *pid, ts_pid_t *p_parent )
183
209k
{
184
209k
    if( pid == p_parent || pid->i_pid == 0x1FFF )
185
0
        return false;
186
187
209k
    if( pid->i_refcount == 0 )
188
183k
    {
189
183k
        assert( pid->type == TYPE_FREE );
190
183k
        switch( i_type )
191
183k
        {
192
0
        case TYPE_FREE: /* nonsense ?*/
193
0
            PIDReset( pid );
194
0
            return true;
195
196
0
        case TYPE_CAT:
197
0
            return true;
198
199
18.6k
        case TYPE_PAT:
200
18.6k
            PIDReset( pid );
201
18.6k
            pid->u.p_pat = ts_pat_New( p_demux );
202
18.6k
            if( !pid->u.p_pat )
203
0
                return false;
204
18.6k
            break;
205
206
20.3k
        case TYPE_PMT:
207
20.3k
            PIDReset( pid );
208
20.3k
            pid->u.p_pmt = ts_pmt_New( p_demux );
209
20.3k
            if( !pid->u.p_pmt )
210
0
                return false;
211
20.3k
            break;
212
213
126k
        case TYPE_STREAM:
214
126k
            PIDReset( pid );
215
126k
            pid->u.p_stream = ts_stream_New( p_demux, p_parent->u.p_pmt );
216
126k
            if( !pid->u.p_stream )
217
0
                return false;
218
126k
            break;
219
220
126k
        case TYPE_SI:
221
17.8k
            PIDReset( pid );
222
17.8k
            pid->u.p_si = ts_si_New( p_demux );
223
17.8k
            if( !pid->u.p_si )
224
0
                return false;
225
17.8k
            break;
226
227
17.8k
        case TYPE_PSIP:
228
979
            PIDReset( pid );
229
979
            pid->u.p_psip = ts_psip_New( p_demux );
230
979
            if( !pid->u.p_psip )
231
0
                return false;
232
979
            break;
233
234
979
        default:
235
0
            assert(false);
236
0
            break;
237
183k
        }
238
239
183k
        pid->i_refcount++;
240
183k
        pid->type = i_type;
241
183k
    }
242
25.1k
    else if( pid->type == i_type && pid->i_refcount < UINT16_MAX )
243
25.1k
    {
244
25.1k
        pid->i_refcount++;
245
25.1k
    }
246
1
    else
247
1
    {
248
1
        if( pid->type != TYPE_FREE )
249
1
            msg_Warn( p_demux, "Tried to redeclare pid %d with another type", pid->i_pid );
250
1
        return false;
251
1
    }
252
253
209k
    return true;
254
209k
}
255
256
void PIDRelease( demux_t *p_demux, ts_pid_t *pid )
257
211k
{
258
211k
    if( pid->i_refcount == 0 )
259
2.26k
    {
260
2.26k
        assert( pid->type == TYPE_FREE );
261
2.26k
        return;
262
2.26k
    }
263
209k
    else if( pid->i_refcount == 1 )
264
183k
    {
265
183k
        pid->i_refcount--;
266
183k
    }
267
25.1k
    else if( pid->i_refcount > 1 )
268
25.1k
    {
269
25.1k
        assert( pid->type != TYPE_FREE && pid->type != TYPE_PAT );
270
25.1k
        pid->i_refcount--;
271
25.1k
    }
272
273
209k
    if( pid->i_refcount == 0 )
274
183k
    {
275
183k
        switch( pid->type )
276
183k
        {
277
0
        default:
278
0
        case TYPE_FREE: /* nonsense ?*/
279
0
            assert( pid->type != TYPE_FREE );
280
0
            break;
281
282
0
        case TYPE_CAT:
283
0
            break;
284
285
18.6k
        case TYPE_PAT:
286
18.6k
            ts_pat_Del( p_demux, pid->u.p_pat );
287
18.6k
            pid->u.p_pat = NULL;
288
18.6k
            break;
289
290
20.3k
        case TYPE_PMT:
291
20.3k
            ts_pmt_Del( p_demux, pid->u.p_pmt );
292
20.3k
            pid->u.p_pmt = NULL;
293
20.3k
            break;
294
295
126k
        case TYPE_STREAM:
296
126k
            ts_stream_Del( p_demux, pid->u.p_stream );
297
126k
            pid->u.p_stream = NULL;
298
126k
            break;
299
300
17.8k
        case TYPE_SI:
301
17.8k
            ts_si_Del( p_demux, pid->u.p_si );
302
17.8k
            pid->u.p_si = NULL;
303
17.8k
            break;
304
305
979
        case TYPE_PSIP:
306
979
            ts_psip_Del( p_demux, pid->u.p_psip );
307
979
            pid->u.p_psip = NULL;
308
979
            break;
309
183k
        }
310
311
183k
        SetPIDFilter( p_demux->p_sys, pid, false );
312
183k
        PIDReset( pid );
313
183k
    }
314
209k
}
315
316
int UpdateHWFilter( demux_sys_t *p_sys, ts_pid_t *p_pid )
317
1.17M
{
318
1.17M
    if( !p_sys->b_access_control )
319
1.15M
        return VLC_EGENERIC;
320
321
18.6k
    return vlc_stream_Control( p_sys->stream, STREAM_SET_PRIVATE_ID_STATE,
322
18.6k
                           p_pid->i_pid, !!(p_pid->i_flags & FLAG_FILTERED) );
323
1.17M
}
324
325
int SetPIDFilter( demux_sys_t *p_sys, ts_pid_t *p_pid, bool b_selected )
326
307k
{
327
307k
    if( b_selected )
328
123k
        p_pid->i_flags |= FLAG_FILTERED;
329
183k
    else
330
183k
        p_pid->i_flags &= ~FLAG_FILTERED;
331
332
307k
    return UpdateHWFilter( p_sys, p_pid );
333
307k
}