/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 | } |