Coverage Report

Created: 2026-05-16 07:42

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