Coverage Report

Created: 2026-08-13 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_sl.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_sl.c : MPEG SL/FMC handling for TS demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2014-2016 - VideoLAN Authors
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_streams.h"
27
#include "ts_pid.h"
28
#include "ts_streams_private.h"
29
#include "ts.h"
30
31
#include "ts_sl.h"
32
33
const es_mpeg4_descriptor_t * GetMPEG4DescByEsId( const ts_pmt_t *pmt, uint16_t i_es_id )
34
1.71M
{
35
395M
    for( int i = 0; pmt->iod && i < ES_DESCRIPTOR_COUNT; i++ )
36
394M
    {
37
394M
        const es_mpeg4_descriptor_t *es_descr = &pmt->iod->es_descr[i];
38
394M
        if( es_descr->i_es_id == i_es_id && es_descr->b_ok )
39
174k
            return es_descr;
40
394M
    }
41
2.28M
    for( int i=0; i<pmt->od.objects.i_size; i++ )
42
2.12M
    {
43
2.12M
        const od_descriptor_t *od = pmt->od.objects.p_elems[i];
44
190M
        for( int j = 0; j < ES_DESCRIPTOR_COUNT; j++ )
45
190M
        {
46
190M
            const es_mpeg4_descriptor_t *es_descr = &od->es_descr[j];
47
190M
            if( es_descr->i_es_id == i_es_id && es_descr->b_ok )
48
1.38M
                return es_descr;
49
190M
        }
50
2.12M
    }
51
161k
    return NULL;
52
1.54M
}
53
54
static ts_es_t * GetPMTESBySLEsId( ts_pmt_t *pmt, uint16_t i_sl_es_id )
55
329k
{
56
1.21M
    for( int i=0; i< pmt->e_streams.i_size; i++ )
57
1.21M
    {
58
1.21M
        ts_es_t *p_es = pmt->e_streams.p_elems[i]->u.p_stream->p_es;
59
1.21M
        if( p_es->i_sl_es_id == i_sl_es_id )
60
328k
            return p_es;
61
1.21M
    }
62
754
    return NULL;
63
329k
}
64
65
bool SetupISO14496LogicalStream( demux_t *p_demux, const decoder_config_descriptor_t *dcd,
66
                                  es_format_t *p_fmt )
67
395k
{
68
395k
    msg_Dbg( p_demux, "     - IOD objecttype: %"PRIx8" streamtype:%"PRIx8,
69
395k
             dcd->i_objectTypeIndication, dcd->i_streamType );
70
71
395k
    if( dcd->i_streamType == 0x04 )    /* VisualStream */
72
183k
    {
73
183k
        switch( dcd->i_objectTypeIndication )
74
183k
        {
75
3.41k
        case 0x0B: /* mpeg4 sub */
76
3.41k
            es_format_Change( p_fmt, SPU_ES, VLC_CODEC_SUBT );
77
3.41k
            break;
78
79
9.40k
        case 0x20: /* mpeg4 */
80
9.40k
            es_format_Change( p_fmt, VIDEO_ES, VLC_CODEC_MP4V );
81
9.40k
            break;
82
113k
        case 0x21: /* h264 */
83
113k
            es_format_Change( p_fmt, VIDEO_ES, VLC_CODEC_H264 );
84
113k
            break;
85
735
        case 0x60:
86
39.9k
        case 0x61:
87
40.9k
        case 0x62:
88
41.3k
        case 0x63:
89
42.3k
        case 0x64:
90
42.6k
        case 0x65: /* mpeg2 */
91
42.7k
        case 0x6a: /* mpeg1 */
92
42.7k
            es_format_Change( p_fmt, VIDEO_ES, VLC_CODEC_MPGV );
93
42.7k
            break;
94
2.58k
        case 0x6c: /* mpeg1 */
95
2.58k
            es_format_Change( p_fmt, VIDEO_ES, VLC_CODEC_JPEG );
96
2.58k
            break;
97
11.3k
        default:
98
11.3k
            break;
99
183k
        }
100
183k
    }
101
212k
    else if( dcd->i_streamType == 0x05 )    /* AudioStream */
102
150k
    {
103
150k
        switch( dcd->i_objectTypeIndication )
104
150k
        {
105
113k
        case 0x40: /* mpeg4 */
106
113k
        case 0x66:
107
114k
        case 0x67:
108
118k
        case 0x68: /* mpeg2 aac */
109
118k
            es_format_Change( p_fmt, AUDIO_ES, VLC_CODEC_MP4A );
110
118k
            break;
111
664
        case 0x69: /* mpeg2 */
112
31.6k
        case 0x6b: /* mpeg1 */
113
31.6k
            es_format_Change( p_fmt, AUDIO_ES, VLC_CODEC_MPGA );
114
31.6k
            break;
115
794
        default:
116
794
            break;
117
150k
        }
118
150k
    }
119
120
395k
    if( p_fmt->i_cat != UNKNOWN_ES )
121
321k
    {
122
321k
        p_fmt->i_extra = __MIN(dcd->i_extra, INT32_MAX);
123
321k
        if( p_fmt->i_extra > 0 )
124
213k
        {
125
213k
            p_fmt->p_extra = malloc( p_fmt->i_extra );
126
213k
            if( p_fmt->p_extra )
127
213k
                memcpy( p_fmt->p_extra, dcd->p_extra, p_fmt->i_extra );
128
0
            else
129
0
                p_fmt->i_extra = 0;
130
213k
        }
131
321k
    }
132
133
395k
    return true;
134
395k
}
135
136
/* Object stream SL in table sections */
137
void SLPackets_Section_Handler( demux_t *p_demux,
138
                                const uint8_t *p_sectiondata, size_t i_sectiondata,
139
                                const uint8_t *p_payloaddata, size_t i_payloaddata,
140
                                void *p_pes_cbdata )
141
122k
{
142
122k
    VLC_UNUSED(p_sectiondata); VLC_UNUSED(i_sectiondata);
143
122k
    demux_sys_t *p_sys = p_demux->p_sys;
144
122k
    ts_stream_t *p_pes = (ts_stream_t *) p_pes_cbdata;
145
122k
    ts_pmt_t *p_pmt = p_pes->p_es->p_program;
146
147
122k
    const es_mpeg4_descriptor_t *p_mpeg4desc = GetMPEG4DescByEsId( p_pmt, p_pes->p_es->i_sl_es_id );
148
122k
    if( p_mpeg4desc && p_mpeg4desc->dec_descr.i_objectTypeIndication == 0x01 &&
149
122k
        p_mpeg4desc->dec_descr.i_streamType == 0x01 /* Object */ )
150
122k
    {
151
122k
        const uint8_t *p_data = p_payloaddata;
152
122k
        size_t i_data = i_payloaddata;
153
154
122k
        od_descriptors_t *p_ods = &p_pmt->od;
155
122k
        sl_header_data header = DecodeSLHeader( i_data, p_data, &p_mpeg4desc->sl_descr );
156
157
122k
        DecodeODCommand( VLC_OBJECT(p_demux), p_ods, i_data - header.i_size, &p_data[header.i_size] );
158
122k
        bool b_changed = false;
159
160
461k
        for( int i=0; i<p_ods->objects.i_size; i++ )
161
339k
        {
162
339k
            od_descriptor_t *p_od = p_ods->objects.p_elems[i];
163
668k
            for( int j = 0; j < ES_DESCRIPTOR_COUNT && p_od->es_descr[j].b_ok; j++ )
164
329k
            {
165
329k
                p_mpeg4desc = &p_od->es_descr[j];
166
329k
                ts_es_t *p_es = GetPMTESBySLEsId( p_pmt, p_mpeg4desc->i_es_id );
167
329k
                es_format_t fmt;
168
329k
                es_format_Init( &fmt, UNKNOWN_ES, 0 );
169
170
329k
                if ( p_mpeg4desc && p_mpeg4desc->b_ok && p_es &&
171
328k
                     SetupISO14496LogicalStream( p_demux, &p_mpeg4desc->dec_descr, &fmt ) &&
172
328k
                     !es_format_IsSimilar( &fmt, &p_es->fmt ) )
173
213k
                {
174
213k
                    fmt.i_id = p_es->fmt.i_id;
175
213k
                    fmt.i_group = p_es->fmt.i_group;
176
213k
                    es_format_Clean( &p_es->fmt );
177
213k
                    p_es->fmt = fmt;
178
179
213k
                    if( p_es->id )
180
195k
                    {
181
195k
                        es_out_Del( p_demux->out, p_es->id );
182
195k
                        p_sys->i_pmt_es--;
183
195k
                    }
184
213k
                    p_es->fmt.b_packetized = true; /* Split by access unit, no sync code */
185
213k
                    p_es->id = es_out_Add( p_demux->out, &p_es->fmt );
186
213k
                    if( p_es->id )
187
213k
                        p_sys->i_pmt_es++;
188
213k
                    b_changed = true;
189
213k
                }
190
115k
                else
191
115k
                    es_format_Clean( &fmt );
192
329k
            }
193
339k
        }
194
195
122k
        if( b_changed )
196
96.5k
            UpdatePESFilters( p_demux, p_sys->seltype == PROGRAM_ALL );
197
122k
    }
198
122k
}
199
200
typedef struct
201
{
202
    block_t     *p_au;
203
    block_t     **pp_au_last;
204
    ts_stream_t *p_stream;
205
206
} SL_stream_processor_context_t;
207
208
static void SL_stream_processor_Delete( ts_stream_processor_t *h )
209
51.5k
{
210
51.5k
    SL_stream_processor_context_t *ctx = (SL_stream_processor_context_t *) h->priv;
211
51.5k
    block_ChainRelease( ctx->p_au );
212
51.5k
    free( ctx );
213
51.5k
    free( h );
214
51.5k
}
215
216
static void SL_stream_processor_Reset( ts_stream_processor_t *h )
217
144
{
218
144
    SL_stream_processor_context_t *ctx = (SL_stream_processor_context_t *) h->priv;
219
144
    block_ChainRelease( ctx->p_au );
220
144
    ctx->p_au = NULL;
221
144
    ctx->pp_au_last = &ctx->p_au;
222
144
}
223
224
static block_t * SL_stream_processor_Push( ts_stream_processor_t *h, uint8_t i_stream_id, block_t *p_block )
225
770k
{
226
770k
    SL_stream_processor_context_t *ctx = (SL_stream_processor_context_t *) h->priv;
227
770k
    ts_es_t *p_es = ctx->p_stream->p_es;
228
770k
    ts_pmt_t *p_pmt = p_es->p_program;
229
230
770k
    if( ((i_stream_id & 0xFE) != 0xFA) /* 0xFA || 0xFB */ )
231
14.4k
    {
232
14.4k
        block_Release( p_block );
233
14.4k
        return NULL;
234
14.4k
    }
235
236
756k
    const es_mpeg4_descriptor_t *p_desc = GetMPEG4DescByEsId( p_pmt, p_es->i_sl_es_id );
237
756k
    if(!p_desc)
238
61.1k
    {
239
61.1k
        block_Release( p_block );
240
61.1k
        p_block = NULL;
241
61.1k
    }
242
695k
    else
243
695k
    {
244
695k
        sl_header_data header = DecodeSLHeader( p_block->i_buffer, p_block->p_buffer,
245
695k
                                                &p_desc->sl_descr );
246
695k
        p_block->i_buffer -= header.i_size;
247
695k
        p_block->p_buffer += header.i_size;
248
695k
        p_block->i_dts = header.i_dts ? header.i_dts : p_block->i_dts;
249
695k
        p_block->i_pts = header.i_pts ? header.i_pts : p_block->i_pts;
250
251
        /* Assemble access units */
252
695k
        if( header.b_au_start && ctx->p_au )
253
4.70k
        {
254
4.70k
            block_ChainRelease( ctx->p_au );
255
4.70k
            ctx->p_au = NULL;
256
4.70k
            ctx->pp_au_last = &ctx->p_au;
257
4.70k
        }
258
695k
        block_ChainLastAppend( &ctx->pp_au_last, p_block );
259
695k
        p_block = NULL;
260
695k
        if( header.b_au_end && ctx->p_au )
261
689k
        {
262
689k
            p_block = block_ChainGather( ctx->p_au );
263
689k
            ctx->p_au = NULL;
264
689k
            ctx->pp_au_last = &ctx->p_au;
265
689k
        }
266
695k
    }
267
268
756k
    return p_block;
269
770k
}
270
271
ts_stream_processor_t *SL_stream_processor_New( ts_stream_t *p_stream )
272
51.5k
{
273
51.5k
    ts_stream_processor_t *h = malloc(sizeof(*h));
274
51.5k
    if(!h)
275
0
        return NULL;
276
277
51.5k
    SL_stream_processor_context_t *ctx = malloc( sizeof(SL_stream_processor_context_t) );
278
51.5k
    if(!ctx)
279
0
    {
280
0
        free(h);
281
0
        return NULL;
282
0
    }
283
51.5k
    ctx->p_au = NULL;
284
51.5k
    ctx->pp_au_last = &ctx->p_au;
285
51.5k
    ctx->p_stream = p_stream;
286
287
51.5k
    h->priv = ctx;
288
51.5k
    h->pf_delete = SL_stream_processor_Delete;
289
51.5k
    h->pf_push = SL_stream_processor_Push;
290
51.5k
    h->pf_reset = SL_stream_processor_Reset;
291
292
51.5k
    return h;
293
51.5k
}