Coverage Report

Created: 2025-10-10 06:26

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