Coverage Report

Created: 2025-12-31 07:55

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