Coverage Report

Created: 2026-06-09 09:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/spudec/spudec.c
Line
Count
Source
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
168
vlc_module_begin ()
49
84
    set_description( N_("DVD subtitles decoder") )
50
84
    set_shortname( N_("DVD subtitles") )
51
84
    set_capability( "spu decoder", 75 )
52
84
    set_subcategory( SUBCAT_INPUT_SCODEC )
53
84
    set_callbacks( DecoderOpen, Close )
54
55
84
    add_bool( "dvdsub-transparency", false,
56
84
              DVDSUBTRANS_DISABLE_TEXT, DVDSUBTRANS_DISABLE_LONGTEXT )
57
84
    add_submodule ()
58
84
    set_description( N_("DVD subtitles packetizer") )
59
84
    set_capability( "spu packetizer", 50 )
60
168
    set_callbacks( PacketizerOpen, Close )
61
84
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
37.1k
{
72
37.1k
    decoder_t     *p_dec = (decoder_t*)p_this;
73
37.1k
    decoder_sys_t *p_sys;
74
75
37.1k
    if( p_dec->fmt_in->i_codec != VLC_CODEC_SPU )
76
35.4k
        return VLC_EGENERIC;
77
78
1.67k
    p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
79
1.67k
    if( !p_sys )
80
0
        return VLC_ENOMEM;
81
82
1.67k
    p_sys->b_packetizer = b_packetizer;
83
1.67k
    p_sys->b_disabletrans = var_InheritBool( p_dec, "dvdsub-transparency" );
84
1.67k
    p_sys->i_spu_size = 0;
85
1.67k
    p_sys->buffer     = NULL;
86
1.67k
    p_sys->buffer_size = 0;
87
1.67k
    p_sys->i_spu      = 0;
88
1.67k
    p_sys->p_block    = NULL;
89
90
1.67k
    if( b_packetizer )
91
839
    {
92
839
        p_dec->pf_packetize  = Packetize;
93
839
        es_format_Copy( &p_dec->fmt_out, p_dec->fmt_in );
94
839
        p_dec->fmt_out.i_codec = VLC_CODEC_SPU;
95
839
    }
96
839
    else
97
839
    {
98
839
        p_dec->fmt_out.i_codec = VLC_CODEC_SPU;
99
839
        p_dec->pf_decode    = Decode;
100
839
    }
101
102
1.67k
    return VLC_SUCCESS;
103
1.67k
}
104
105
static int DecoderOpen( vlc_object_t *p_this )
106
17.0k
{
107
17.0k
    return OpenCommon( p_this, false );
108
17.0k
}
109
110
static int PacketizerOpen( vlc_object_t *p_this )
111
20.0k
{
112
20.0k
    return OpenCommon( p_this, true );
113
20.0k
}
114
115
/*****************************************************************************
116
 * Close:
117
 *****************************************************************************/
118
static void Close( vlc_object_t *p_this )
119
1.67k
{
120
1.67k
    decoder_t     *p_dec = (decoder_t*)p_this;
121
1.67k
    decoder_sys_t *p_sys = p_dec->p_sys;
122
123
1.67k
    if( p_sys->p_block )
124
85
    {
125
85
        block_ChainRelease( p_sys->p_block );
126
85
    }
127
128
1.67k
    free( p_sys->buffer );
129
1.67k
    free( p_sys );
130
1.67k
}
131
132
/*****************************************************************************
133
 * Decode:
134
 *****************************************************************************/
135
static int Decode( decoder_t *p_dec, block_t *p_block )
136
22.9k
{
137
22.9k
    decoder_sys_t *p_sys = p_dec->p_sys;
138
22.9k
    block_t       *p_spu_block;
139
140
22.9k
    if( p_block == NULL ) /* No Drain */
141
19.0k
        return VLCDEC_SUCCESS;
142
3.90k
    p_spu_block = Reassemble( p_dec, p_block );
143
144
3.90k
    if( ! p_spu_block )
145
0
    {
146
0
        return VLCDEC_SUCCESS;
147
0
    }
148
149
3.90k
    size_t block_size;
150
3.90k
    vlc_frame_ChainProperties( p_spu_block, NULL, &block_size, NULL );
151
3.90k
    if ( p_sys->buffer_size < block_size )
152
437
    {
153
437
        void *bigger = realloc( p_sys->buffer, block_size );
154
437
        if ( unlikely(bigger == NULL) )
155
0
        {
156
0
            return VLCDEC_ECRITICAL;
157
0
        }
158
437
        p_sys->buffer = bigger;
159
437
        p_sys->buffer_size = block_size;
160
437
    }
161
3.90k
    p_sys->i_spu = block_ChainExtract( p_spu_block, p_sys->buffer, block_size );
162
3.90k
    p_sys->i_pts = p_spu_block->i_pts;
163
3.90k
    block_ChainRelease( p_spu_block );
164
165
    /* Parse and decode */
166
3.90k
    ParsePacket( p_dec, decoder_QueueSub );
167
168
    /* reinit context */
169
3.90k
    p_sys->i_spu_size = 0;
170
3.90k
    p_sys->i_rle_size = 0;
171
3.90k
    p_sys->i_spu      = 0;
172
3.90k
    p_sys->p_block    = NULL;
173
174
3.90k
    return VLCDEC_SUCCESS;
175
3.90k
}
176
177
/*****************************************************************************
178
 * Packetize:
179
 *****************************************************************************/
180
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
181
22.9k
{
182
22.9k
    decoder_sys_t *p_sys = p_dec->p_sys;
183
22.9k
    if( pp_block == NULL ) /* No Drain */
184
839
        return NULL;
185
22.1k
    block_t *p_block = *pp_block; *pp_block = NULL;
186
22.1k
    if( p_block == NULL )
187
3.90k
        return NULL;
188
189
18.2k
    block_t *p_spu = Reassemble( p_dec, p_block );
190
191
18.2k
    if( ! p_spu )
192
14.3k
    {
193
14.3k
        return NULL;
194
14.3k
    }
195
196
3.90k
    p_spu->i_dts = p_spu->i_pts;
197
3.90k
    p_spu->i_length = VLC_TICK_INVALID;
198
199
    /* reinit context */
200
3.90k
    p_sys->i_spu_size = 0;
201
3.90k
    p_sys->i_rle_size = 0;
202
3.90k
    p_sys->i_spu      = 0;
203
3.90k
    p_sys->p_block    = NULL;
204
205
3.90k
    return block_ChainGather( p_spu );
206
18.2k
}
207
208
/*****************************************************************************
209
 * Reassemble:
210
 *****************************************************************************/
211
static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
212
22.1k
{
213
22.1k
    decoder_sys_t *p_sys = p_dec->p_sys;
214
215
22.1k
    if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
216
0
    {
217
0
        block_Release( p_block );
218
0
        return NULL;
219
0
    }
220
221
22.1k
    if( p_sys->i_spu_size <= 0 &&
222
9.05k
        ( p_block->i_pts == VLC_TICK_INVALID || p_block->i_buffer < 4 ) )
223
205
    {
224
205
        msg_Dbg( p_dec, "invalid starting packet (size < 4 or pts <=0)" );
225
205
        msg_Dbg( p_dec, "spu size: %d, i_pts: %"PRId64" i_buffer: %zu",
226
205
                 p_sys->i_spu_size, p_block->i_pts, p_block->i_buffer );
227
205
        block_Release( p_block );
228
205
        return NULL;
229
205
    }
230
231
21.9k
    block_ChainAppend( &p_sys->p_block, p_block );
232
21.9k
    p_sys->i_spu += p_block->i_buffer;
233
234
21.9k
    if( p_sys->i_spu_size <= 0 )
235
8.84k
    {
236
8.84k
        p_sys->i_spu_size = ( p_block->p_buffer[0] << 8 )|
237
8.84k
            p_block->p_buffer[1];
238
8.84k
        p_sys->i_rle_size = ( ( p_block->p_buffer[2] << 8 )|
239
8.84k
            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
8.84k
        if( p_sys->i_spu_size <= 0 || p_sys->i_rle_size >= p_sys->i_spu_size )
245
946
        {
246
946
            p_sys->i_spu_size = 0;
247
946
            p_sys->i_rle_size = 0;
248
946
            p_sys->i_spu      = 0;
249
946
            p_sys->p_block    = NULL;
250
251
946
            block_Release( p_block );
252
946
            return NULL;
253
946
        }
254
8.84k
    }
255
256
21.0k
    if( p_sys->i_spu >= p_sys->i_spu_size )
257
7.81k
    {
258
        /* We have a complete sub */
259
7.81k
        if( p_sys->i_spu > p_sys->i_spu_size )
260
7.81k
            msg_Dbg( p_dec, "SPU packets size=%d should be %d",
261
7.81k
                     p_sys->i_spu, p_sys->i_spu_size );
262
263
7.81k
        return p_sys->p_block;
264
7.81k
    }
265
13.1k
    return NULL;
266
21.0k
}