Coverage Report

Created: 2026-04-12 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mpeg/ts_metadata.c
Line
Count
Source
1
/*****************************************************************************
2
 * ts_metadata.c : TS demuxer metadata handling
3
 *****************************************************************************
4
 * Copyright (C) 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_meta.h>
25
#include <vlc_es_out.h>
26
#include <vlc_block.h>
27
28
#include "ts_pid.h"
29
#include "ts_streams.h"
30
#include "ts_streams_private.h"
31
#include "ts_metadata.h"
32
33
#include "../../meta_engine/ID3Tag.h"
34
#include "../../meta_engine/ID3Meta.h"
35
36
#include <assert.h>
37
38
static int ID3TAG_Parse_Handler( uint32_t i_tag, const uint8_t *p_payload,
39
                                 size_t i_payload, void *p_priv )
40
0
{
41
0
    vlc_meta_t *p_meta = (vlc_meta_t *) p_priv;
42
43
0
    (void) ID3HandleTag( p_payload, i_payload, i_tag, p_meta, NULL );
44
45
0
    return VLC_SUCCESS;
46
0
}
47
48
typedef struct
49
{
50
    es_out_t *out;
51
    ts_stream_t *p_stream;
52
    block_t *p_head;
53
    block_t **pp_tail;
54
    uint8_t i_sequence_number;
55
} Metadata_stream_processor_context_t;
56
57
static void Metadata_stream_processor_Reset( ts_stream_processor_t *h )
58
0
{
59
0
    Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv;
60
0
    block_ChainRelease(ctx->p_head);
61
0
    ctx->p_head = NULL;
62
0
    ctx->pp_tail = &ctx->p_head;
63
0
}
64
65
static void Metadata_stream_processor_Delete( ts_stream_processor_t *h )
66
0
{
67
0
    Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv;
68
0
    block_ChainRelease(ctx->p_head);
69
0
    free( ctx );
70
0
    free( h );
71
0
}
72
73
static block_t * Metadata_stream_processor_AggregateMAU( ts_stream_processor_t *h,
74
                                                         uint8_t i_sequence, block_t *p_block,
75
                                                         size_t i_cellsize )
76
0
{
77
0
    Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv;
78
0
79
0
    bool b_corrupt = ctx->p_head && i_sequence != ((ctx->i_sequence_number + 1) & 0xFF);
80
0
81
0
    if( unlikely(p_block->i_buffer > i_cellsize) )
82
0
    {
83
0
        block_t *cell = block_Duplicate( p_block );
84
0
        if( cell )
85
0
        {
86
0
            cell->i_buffer = i_cellsize;
87
0
            block_ChainLastAppend( &ctx->pp_tail, cell );
88
0
        }
89
0
        p_block->i_buffer -= i_cellsize;
90
0
        p_block->i_buffer += i_cellsize;
91
0
    }
92
0
    else
93
0
    {
94
0
        assert( p_block->i_buffer == i_cellsize );
95
0
        block_ChainLastAppend( &ctx->pp_tail, p_block );
96
0
        p_block = NULL;
97
0
    }
98
0
99
0
    ctx->i_sequence_number = i_sequence;
100
0
    if( b_corrupt )
101
0
        Metadata_stream_processor_Reset( h );
102
0
103
0
    return p_block;
104
0
}
105
106
static block_t * Metadata_stream_processor_OutputMAU( ts_stream_processor_t *h )
107
0
{
108
0
    Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv;
109
0
110
0
    block_t *p_chain = ctx->p_head;
111
0
    if( !p_chain )
112
0
        return NULL;
113
0
    ctx->p_head = NULL;
114
0
    ctx->pp_tail = &ctx->p_head;
115
0
    return block_ChainGather( p_chain );
116
0
}
117
118
static block_t * Metadata_stream_processor_PushMAU( ts_stream_processor_t *h,
119
                                                    const ts_es_t *p_es, block_t *p_block )
120
0
{
121
0
    block_t *p_return_chain = NULL;
122
0
    block_t **pp_return = &p_return_chain;
123
0
124
0
    while( p_block->i_buffer >= 5 )
125
0
    {
126
0
        const uint8_t i_service_id = p_block->p_buffer[0];
127
0
        const uint8_t i_sequence = p_block->p_buffer[1];
128
0
        const uint8_t i_fragment_indication = p_block->p_buffer[2] >> 6;
129
0
        const uint16_t i_length = GetWBE(&p_block->p_buffer[3]);
130
0
131
0
        p_block->i_buffer -= 5;
132
0
        p_block->p_buffer += 5;
133
0
134
0
        if( p_block->i_buffer < i_length )
135
0
            break;
136
0
137
0
        if( i_service_id == p_es->metadata.i_service_id )
138
0
        {
139
0
            if( i_fragment_indication == 0x03 ) /* FULL AU */
140
0
            {
141
0
                Metadata_stream_processor_Reset( h ); /* flush anything that not went to last frag */
142
0
                p_block = Metadata_stream_processor_AggregateMAU( h, i_sequence, p_block, i_length );
143
0
            }
144
0
            else
145
0
            {
146
0
                if( i_fragment_indication == 0x02 ) /* First */
147
0
                    Metadata_stream_processor_Reset( h ); /* flush anything that not went to last frag */
148
0
                p_block = Metadata_stream_processor_AggregateMAU( h, i_sequence, p_block, i_length );
149
0
                if( i_fragment_indication == 0x01 ) /* Last */
150
0
                {
151
0
                    block_t *out = Metadata_stream_processor_OutputMAU( h );
152
0
                    if( out )
153
0
                        block_ChainLastAppend( &pp_return, out );
154
0
                }
155
0
            }
156
0
        }
157
0
158
0
        if( !p_block )
159
0
            break;
160
0
161
0
        p_block->i_buffer -= i_length;
162
0
        p_block->i_buffer += i_length;
163
0
    };
164
0
165
0
    if( p_block )
166
0
        block_Release( p_block );
167
0
168
0
    return p_return_chain;
169
0
}
170
171
static block_t * Metadata_stream_processor_Push( ts_stream_processor_t *h, uint8_t i_stream_id, block_t *p_block )
172
0
{
173
0
    Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv;
174
0
    ts_es_t *p_es = ctx->p_stream->p_es;
175
176
0
    if( i_stream_id == 0xbd && /* Transport in PES packets, 2.12.3 */
177
0
        p_es->metadata.i_format_identifier == METADATA_IDENTIFIER_ID3 )
178
0
    {
179
0
        vlc_meta_t *p_meta = vlc_meta_New();
180
0
        if( p_meta )
181
0
        {
182
0
            (void) ID3TAG_Parse( p_block->p_buffer, p_block->i_buffer, ID3TAG_Parse_Handler, p_meta );
183
0
            es_out_Control( ctx->out, ES_OUT_SET_GROUP_META, p_es->p_program->i_number, p_meta );
184
0
            vlc_meta_Delete( p_meta );
185
0
        }
186
0
    }
187
188
0
    return p_block;
189
0
}
190
191
ts_stream_processor_t *Metadata_stream_processor_New( ts_stream_t *p_stream, es_out_t *out )
192
0
{
193
0
    ts_stream_processor_t *h = malloc(sizeof(*h));
194
0
    if(!h)
195
0
        return NULL;
196
197
0
    Metadata_stream_processor_context_t *ctx = malloc( sizeof(Metadata_stream_processor_context_t) );
198
0
    if(!ctx)
199
0
    {
200
0
        free(h);
201
0
        return NULL;
202
0
    }
203
0
    ctx->out = out;
204
0
    ctx->p_stream = p_stream;
205
0
    ctx->i_sequence_number = 0;
206
0
    ctx->p_head = NULL;
207
0
    ctx->pp_tail = &ctx->p_head;
208
209
0
    h->priv = ctx;
210
0
    h->pf_delete = Metadata_stream_processor_Delete;
211
0
    h->pf_push = Metadata_stream_processor_Push;
212
0
    h->pf_reset = Metadata_stream_processor_Reset;
213
214
0
    return h;
215
0
}