Coverage Report

Created: 2026-09-03 07:09

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
34.1k
#define PID_ALLOC_CHUNK 16
36
37
void ts_pid_list_Init( ts_pid_list_t *p_list )
38
16.3k
{
39
16.3k
    p_list->dummy.i_pid = 8191;
40
16.3k
    p_list->dummy.i_flags = FLAG_SEEN;
41
16.3k
    p_list->base_si.i_pid = 0x1FFB;
42
16.3k
    p_list->pp_all = NULL;
43
16.3k
    p_list->i_all = 0;
44
16.3k
    p_list->i_all_alloc = 0;
45
16.3k
    p_list->i_last_pid = 0;
46
16.3k
    p_list->p_last = NULL;
47
16.3k
}
48
49
void ts_pid_list_Release( demux_t *p_demux, ts_pid_list_t *p_list )
50
16.3k
{
51
140k
    for( int i = 0; i < p_list->i_all; i++ )
52
123k
    {
53
123k
        ts_pid_t *pid = p_list->pp_all[i];
54
123k
#ifndef NDEBUG
55
123k
        if( pid->type != TYPE_FREE )
56
123k
            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
123k
        free( pid );
61
123k
    }
62
16.3k
    free( p_list->pp_all );
63
16.3k
}
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.47M
{
73
8.47M
    struct searchkey *p_key = (void *)key;
74
8.47M
    ts_pid_t *const *pp_pid = other;
75
76
8.47M
    ts_pid_t *p_pid = *pp_pid;
77
8.47M
    p_key->pp_last = other;
78
8.47M
    return ( p_key->i_pid >= p_pid->i_pid ) ? p_key->i_pid - p_pid->i_pid : -1;
79
8.47M
}
80
81
ts_pid_t * ts_pid_Get( ts_pid_list_t *p_list, uint16_t i_pid )
82
10.0M
{
83
10.0M
    switch( i_pid )
84
10.0M
    {
85
3.64M
        case 0:
86
3.64M
            return &p_list->pat;
87
71.3k
        case 0x1FFB:
88
71.3k
            return &p_list->base_si;
89
420k
        case 0x1FFF:
90
420k
            return &p_list->dummy;
91
5.91M
        default:
92
5.91M
            if( p_list->i_last_pid == i_pid )
93
2.80M
                return p_list->p_last;
94
3.11M
        break;
95
10.0M
    }
96
97
3.11M
    size_t i_index = 0;
98
3.11M
    ts_pid_t *p_pid = NULL;
99
100
3.11M
    if( p_list->pp_all )
101
3.10M
    {
102
3.10M
        struct searchkey pidkey;
103
3.10M
        pidkey.i_pid = i_pid;
104
3.10M
        pidkey.pp_last = NULL;
105
106
3.10M
        ts_pid_t **pp_pidk = bsearch( &pidkey, p_list->pp_all, p_list->i_all,
107
3.10M
                                      sizeof(ts_pid_t *), ts_bsearch_searchkey_Compare );
108
3.10M
        if ( pp_pidk )
109
2.99M
            p_pid = *pp_pidk;
110
107k
        else
111
107k
            i_index = (pidkey.pp_last - p_list->pp_all); /* Last visited index */
112
3.10M
    }
113
114
3.11M
    if( p_pid == NULL )
115
123k
    {
116
123k
        if( p_list->i_all >= p_list->i_all_alloc )
117
17.0k
        {
118
17.0k
            ts_pid_t **p_realloc = realloc( p_list->pp_all,
119
17.0k
                                            (p_list->i_all_alloc + PID_ALLOC_CHUNK) * sizeof(ts_pid_t *) );
120
17.0k
            if( !p_realloc )
121
0
            {
122
0
                abort();
123
                //return NULL;
124
0
            }
125
17.0k
            p_list->pp_all = p_realloc;
126
17.0k
            p_list->i_all_alloc += PID_ALLOC_CHUNK;
127
17.0k
        }
128
129
123k
        p_pid = calloc( 1, sizeof(*p_pid) );
130
123k
        if( !p_pid )
131
0
        {
132
0
            abort();
133
            //return NULL;
134
0
        }
135
136
123k
        p_pid->i_cc  = 0xff;
137
123k
        p_pid->i_pid = i_pid;
138
139
        /* Do insertion based on last bsearch mid point */
140
123k
        if( p_list->i_all )
141
107k
        {
142
107k
            if( p_list->pp_all[i_index]->i_pid < i_pid )
143
50.7k
                i_index++;
144
145
107k
            memmove( &p_list->pp_all[i_index + 1],
146
107k
                    &p_list->pp_all[i_index],
147
107k
                    (p_list->i_all - i_index) * sizeof(ts_pid_t *) );
148
107k
        }
149
150
123k
        p_list->pp_all[i_index] = p_pid;
151
123k
        p_list->i_all++;
152
153
123k
    }
154
155
3.11M
    p_list->p_last = p_pid;
156
3.11M
    p_list->i_last_pid = i_pid;
157
158
3.11M
    return p_pid;
159
3.11M
}
160
161
ts_pid_t * ts_pid_Next( ts_pid_list_t *p_list, ts_pid_next_context_t *p_ctx )
162
3.28k
{
163
3.28k
    if( likely(p_list->i_all && p_ctx) )
164
3.28k
    {
165
3.28k
        if( p_ctx->i_pos < p_list->i_all )
166
2.90k
            return p_list->pp_all[p_ctx->i_pos++];
167
3.28k
    }
168
387
    return NULL;
169
3.28k
}
170
171
static void PIDReset( ts_pid_t *pid )
172
346k
{
173
346k
    assert(pid->i_refcount == 0);
174
346k
    pid->i_cc       = 0xff;
175
346k
    pid->i_dup      = 0;
176
346k
    pid->i_flags    &= ~FLAG_SCRAMBLED;
177
346k
    pid->type = TYPE_FREE;
178
346k
    pid->i_scramble_counter = 0;
179
346k
    memset(pid->prevpktbytes, 0, PREVPKTKEEPBYTES);
180
346k
}
181
182
bool PIDSetup( demux_t *p_demux, ts_pid_type_t i_type, ts_pid_t *pid, ts_pid_t *p_parent )
183
199k
{
184
199k
    if( pid == p_parent || pid->i_pid == 0x1FFF )
185
0
        return false;
186
187
199k
    if( pid->i_refcount == 0 )
188
173k
    {
189
173k
        assert( pid->type == TYPE_FREE );
190
173k
        switch( i_type )
191
173k
        {
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
16.3k
        case TYPE_PAT:
200
16.3k
            PIDReset( pid );
201
16.3k
            pid->u.p_pat = ts_pat_New( p_demux );
202
16.3k
            if( !pid->u.p_pat )
203
0
                return false;
204
16.3k
            break;
205
206
18.0k
        case TYPE_PMT:
207
18.0k
            PIDReset( pid );
208
18.0k
            pid->u.p_pmt = ts_pmt_New( p_demux );
209
18.0k
            if( !pid->u.p_pmt )
210
0
                return false;
211
18.0k
            break;
212
213
122k
        case TYPE_STREAM:
214
122k
            PIDReset( pid );
215
122k
            pid->u.p_stream = ts_stream_New( p_demux, p_parent->u.p_pmt );
216
122k
            if( !pid->u.p_stream )
217
0
                return false;
218
122k
            break;
219
220
122k
        case TYPE_SI:
221
15.7k
            PIDReset( pid );
222
15.7k
            pid->u.p_si = ts_si_New( p_demux );
223
15.7k
            if( !pid->u.p_si )
224
0
                return false;
225
15.7k
            break;
226
227
15.7k
        case TYPE_PSIP:
228
638
            PIDReset( pid );
229
638
            pid->u.p_psip = ts_psip_New( p_demux );
230
638
            if( !pid->u.p_psip )
231
0
                return false;
232
638
            break;
233
234
638
        default:
235
0
            assert(false);
236
0
            break;
237
173k
        }
238
239
173k
        pid->i_refcount++;
240
173k
        pid->type = i_type;
241
173k
    }
242
26.1k
    else if( pid->type == i_type && pid->i_refcount < UINT16_MAX )
243
26.1k
    {
244
26.1k
        pid->i_refcount++;
245
26.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
199k
    return true;
254
199k
}
255
256
void PIDRelease( demux_t *p_demux, ts_pid_t *pid )
257
200k
{
258
200k
    if( pid->i_refcount == 0 )
259
1.06k
    {
260
1.06k
        assert( pid->type == TYPE_FREE );
261
1.06k
        return;
262
1.06k
    }
263
199k
    else if( pid->i_refcount == 1 )
264
173k
    {
265
173k
        pid->i_refcount--;
266
173k
    }
267
26.1k
    else if( pid->i_refcount > 1 )
268
26.1k
    {
269
26.1k
        assert( pid->type != TYPE_FREE && pid->type != TYPE_PAT );
270
26.1k
        pid->i_refcount--;
271
26.1k
    }
272
273
199k
    if( pid->i_refcount == 0 )
274
173k
    {
275
173k
        switch( pid->type )
276
173k
        {
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
16.3k
        case TYPE_PAT:
286
16.3k
            ts_pat_Del( p_demux, pid->u.p_pat );
287
16.3k
            pid->u.p_pat = NULL;
288
16.3k
            break;
289
290
18.0k
        case TYPE_PMT:
291
18.0k
            ts_pmt_Del( p_demux, pid->u.p_pmt );
292
18.0k
            pid->u.p_pmt = NULL;
293
18.0k
            break;
294
295
122k
        case TYPE_STREAM:
296
122k
            ts_stream_Del( p_demux, pid->u.p_stream );
297
122k
            pid->u.p_stream = NULL;
298
122k
            break;
299
300
15.7k
        case TYPE_SI:
301
15.7k
            ts_si_Del( p_demux, pid->u.p_si );
302
15.7k
            pid->u.p_si = NULL;
303
15.7k
            break;
304
305
638
        case TYPE_PSIP:
306
638
            ts_psip_Del( p_demux, pid->u.p_psip );
307
638
            pid->u.p_psip = NULL;
308
638
            break;
309
173k
        }
310
311
173k
        SetPIDFilter( p_demux->p_sys, pid, false );
312
173k
        PIDReset( pid );
313
173k
    }
314
199k
}
315
316
int UpdateHWFilter( demux_sys_t *p_sys, ts_pid_t *p_pid )
317
1.08M
{
318
1.08M
    if( !p_sys->b_access_control )
319
1.06M
        return VLC_EGENERIC;
320
321
16.3k
    return vlc_stream_Control( p_sys->stream, STREAM_SET_PRIVATE_ID_STATE,
322
16.3k
                           p_pid->i_pid, !!(p_pid->i_flags & FLAG_FILTERED) );
323
1.08M
}
324
325
int SetPIDFilter( demux_sys_t *p_sys, ts_pid_t *p_pid, bool b_selected )
326
289k
{
327
289k
    if( b_selected )
328
116k
        p_pid->i_flags |= FLAG_FILTERED;
329
173k
    else
330
173k
        p_pid->i_flags &= ~FLAG_FILTERED;
331
332
289k
    return UpdateHWFilter( p_sys, p_pid );
333
289k
}