Coverage Report

Created: 2025-07-18 08:04

/src/vlc/modules/codec/spudec/spudec.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * spudec.c : SPU decoder thread
3
 *****************************************************************************
4
 * Copyright (C) 2000-2001, 2006 VLC authors and VideoLAN
5
 *
6
 * Authors: Sam Hocevar <sam@zoy.org>
7
 *          Laurent Aimar <fenrir@via.ecp.fr>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
/*****************************************************************************
25
 * Preamble
26
 *****************************************************************************/
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33
#include <vlc_codec.h>
34
35
#include "spudec.h"
36
37
/*****************************************************************************
38
 * Module descriptor.
39
 *****************************************************************************/
40
static int  DecoderOpen   ( vlc_object_t * );
41
static int  PacketizerOpen( vlc_object_t * );
42
static void Close         ( vlc_object_t * );
43
44
#define DVDSUBTRANS_DISABLE_TEXT N_("Disable DVD subtitle transparency")
45
#define DVDSUBTRANS_DISABLE_LONGTEXT N_("Removes all transparency effects " \
46
                                        "used in DVD subtitles.")
47
48
104
vlc_module_begin ()
49
52
    set_description( N_("DVD subtitles decoder") )
50
52
    set_shortname( N_("DVD subtitles") )
51
52
    set_capability( "spu decoder", 75 )
52
52
    set_subcategory( SUBCAT_INPUT_SCODEC )
53
52
    set_callbacks( DecoderOpen, Close )
54
55
52
    add_bool( "dvdsub-transparency", false,
56
52
              DVDSUBTRANS_DISABLE_TEXT, DVDSUBTRANS_DISABLE_LONGTEXT )
57
52
    add_submodule ()
58
52
    set_description( N_("DVD subtitles packetizer") )
59
52
    set_capability( "spu packetizer", 50 )
60
104
    set_callbacks( PacketizerOpen, Close )
61
52
vlc_module_end ()
62
63
/*****************************************************************************
64
 * Local prototypes
65
 *****************************************************************************/
66
static block_t *      Reassemble( decoder_t *, block_t * );
67
static int            Decode    ( decoder_t *, block_t * );
68
static block_t *      Packetize ( decoder_t *, block_t ** );
69
70
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
71
24.0k
{
72
24.0k
    decoder_t     *p_dec = (decoder_t*)p_this;
73
24.0k
    decoder_sys_t *p_sys;
74
75
24.0k
    if( p_dec->fmt_in->i_codec != VLC_CODEC_SPU )
76
23.8k
        return VLC_EGENERIC;
77
78
232
    p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
79
232
    if( !p_sys )
80
0
        return VLC_ENOMEM;
81
82
232
    p_sys->b_packetizer = b_packetizer;
83
232
    p_sys->b_disabletrans = var_InheritBool( p_dec, "dvdsub-transparency" );
84
232
    p_sys->i_spu_size = 0;
85
232
    p_sys->buffer     = NULL;
86
232
    p_sys->buffer_size = 0;
87
232
    p_sys->i_spu      = 0;
88
232
    p_sys->p_block    = NULL;
89
90
232
    if( b_packetizer )
91
116
    {
92
116
        p_dec->pf_packetize  = Packetize;
93
116
        es_format_Copy( &p_dec->fmt_out, p_dec->fmt_in );
94
116
        p_dec->fmt_out.i_codec = VLC_CODEC_SPU;
95
116
    }
96
116
    else
97
116
    {
98
116
        p_dec->fmt_out.i_codec = VLC_CODEC_SPU;
99
116
        p_dec->pf_decode    = Decode;
100
116
    }
101
102
232
    return VLC_SUCCESS;
103
232
}
104
105
static int DecoderOpen( vlc_object_t *p_this )
106
11.9k
{
107
11.9k
    return OpenCommon( p_this, false );
108
11.9k
}
109
110
static int PacketizerOpen( vlc_object_t *p_this )
111
12.0k
{
112
12.0k
    return OpenCommon( p_this, true );
113
12.0k
}
114
115
/*****************************************************************************
116
 * Close:
117
 *****************************************************************************/
118
static void Close( vlc_object_t *p_this )
119
232
{
120
232
    decoder_t     *p_dec = (decoder_t*)p_this;
121
232
    decoder_sys_t *p_sys = p_dec->p_sys;
122
123
232
    if( p_sys->p_block )
124
70
    {
125
70
        block_ChainRelease( p_sys->p_block );
126
70
    }
127
128
232
    free( p_sys->buffer );
129
232
    free( p_sys );
130
232
}
131
132
/*****************************************************************************
133
 * Decode:
134
 *****************************************************************************/
135
static int Decode( decoder_t *p_dec, block_t *p_block )
136
46.9k
{
137
46.9k
    decoder_sys_t *p_sys = p_dec->p_sys;
138
46.9k
    block_t       *p_spu_block;
139
140
46.9k
    if( p_block == NULL ) /* No Drain */
141
45.4k
        return VLCDEC_SUCCESS;
142
1.50k
    p_spu_block = Reassemble( p_dec, p_block );
143
144
1.50k
    if( ! p_spu_block )
145
0
    {
146
0
        return VLCDEC_SUCCESS;
147
0
    }
148
149
1.50k
    size_t block_size;
150
1.50k
    vlc_frame_ChainProperties( p_spu_block, NULL, &block_size, NULL );
151
1.50k
    if ( p_sys->buffer_size < block_size )
152
136
    {
153
136
        void *bigger = realloc( p_sys->buffer, block_size );
154
136
        if ( unlikely(bigger == NULL) )
155
0
        {
156
0
            return VLCDEC_ECRITICAL;
157
0
        }
158
136
        p_sys->buffer = bigger;
159
136
        p_sys->buffer_size = block_size;
160
136
    }
161
1.50k
    p_sys->i_spu = block_ChainExtract( p_spu_block, p_sys->buffer, block_size );
162
1.50k
    p_sys->i_pts = p_spu_block->i_pts;
163
1.50k
    block_ChainRelease( p_spu_block );
164
165
    /* Parse and decode */
166
1.50k
    ParsePacket( p_dec, decoder_QueueSub );
167
168
    /* reinit context */
169
1.50k
    p_sys->i_spu_size = 0;
170
1.50k
    p_sys->i_rle_size = 0;
171
1.50k
    p_sys->i_spu      = 0;
172
1.50k
    p_sys->p_block    = NULL;
173
174
1.50k
    return VLCDEC_SUCCESS;
175
1.50k
}
176
177
/*****************************************************************************
178
 * Packetize:
179
 *****************************************************************************/
180
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
181
46.9k
{
182
46.9k
    decoder_sys_t *p_sys = p_dec->p_sys;
183
46.9k
    if( pp_block == NULL ) /* No Drain */
184
116
        return NULL;
185
46.8k
    block_t *p_block = *pp_block; *pp_block = NULL;
186
46.8k
    if( p_block == NULL )
187
1.50k
        return NULL;
188
189
45.3k
    block_t *p_spu = Reassemble( p_dec, p_block );
190
191
45.3k
    if( ! p_spu )
192
43.8k
    {
193
43.8k
        return NULL;
194
43.8k
    }
195
196
1.50k
    p_spu->i_dts = p_spu->i_pts;
197
1.50k
    p_spu->i_length = VLC_TICK_INVALID;
198
199
    /* reinit context */
200
1.50k
    p_sys->i_spu_size = 0;
201
1.50k
    p_sys->i_rle_size = 0;
202
1.50k
    p_sys->i_spu      = 0;
203
1.50k
    p_sys->p_block    = NULL;
204
205
1.50k
    return block_ChainGather( p_spu );
206
45.3k
}
207
208
/*****************************************************************************
209
 * Reassemble:
210
 *****************************************************************************/
211
static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
212
46.8k
{
213
46.8k
    decoder_sys_t *p_sys = p_dec->p_sys;
214
215
46.8k
    if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
216
0
    {
217
0
        block_Release( p_block );
218
0
        return NULL;
219
0
    }
220
221
46.8k
    if( p_sys->i_spu_size <= 0 &&
222
46.8k
        ( p_block->i_pts == VLC_TICK_INVALID || p_block->i_buffer < 4 ) )
223
1
    {
224
1
        msg_Dbg( p_dec, "invalid starting packet (size < 4 or pts <=0)" );
225
1
        msg_Dbg( p_dec, "spu size: %d, i_pts: %"PRId64" i_buffer: %zu",
226
1
                 p_sys->i_spu_size, p_block->i_pts, p_block->i_buffer );
227
1
        block_Release( p_block );
228
1
        return NULL;
229
1
    }
230
231
46.8k
    block_ChainAppend( &p_sys->p_block, p_block );
232
46.8k
    p_sys->i_spu += p_block->i_buffer;
233
234
46.8k
    if( p_sys->i_spu_size <= 0 )
235
9.20k
    {
236
9.20k
        p_sys->i_spu_size = ( p_block->p_buffer[0] << 8 )|
237
9.20k
            p_block->p_buffer[1];
238
9.20k
        p_sys->i_rle_size = ( ( p_block->p_buffer[2] << 8 )|
239
9.20k
            p_block->p_buffer[3] ) - 4;
240
241
        /* msg_Dbg( p_dec, "i_spu_size=%d i_rle=%d",
242
                    p_sys->i_spu_size, p_sys->i_rle_size ); */
243
244
9.20k
        if( p_sys->i_spu_size <= 0 || p_sys->i_rle_size >= p_sys->i_spu_size )
245
6.11k
        {
246
6.11k
            p_sys->i_spu_size = 0;
247
6.11k
            p_sys->i_rle_size = 0;
248
6.11k
            p_sys->i_spu      = 0;
249
6.11k
            p_sys->p_block    = NULL;
250
251
6.11k
            block_Release( p_block );
252
6.11k
            return NULL;
253
6.11k
        }
254
9.20k
    }
255
256
40.6k
    if( p_sys->i_spu >= p_sys->i_spu_size )
257
3.01k
    {
258
        /* We have a complete sub */
259
3.01k
        if( p_sys->i_spu > p_sys->i_spu_size )
260
3.01k
            msg_Dbg( p_dec, "SPU packets size=%d should be %d",
261
3.01k
                     p_sys->i_spu, p_sys->i_spu_size );
262
263
3.01k
        return p_sys->p_block;
264
3.01k
    }
265
37.6k
    return NULL;
266
40.6k
}