/src/vlc/modules/codec/cvdsub.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * cvdsub.c : CVD Subtitle decoder |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2003, 2004 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Rocky Bernstein |
7 | | * Gildas Bazin <gbazin@videolan.org> |
8 | | * Julio Sanchez Fernandez (http://subhandler.sourceforge.net) |
9 | | * Laurent Aimar <fenrir@via.ecp.fr> |
10 | | * |
11 | | * This program is free software; you can redistribute it and/or modify it |
12 | | * under the terms of the GNU Lesser General Public License as published by |
13 | | * the Free Software Foundation; either version 2.1 of the License, or |
14 | | * (at your option) any later version. |
15 | | * |
16 | | * This program is distributed in the hope that it will be useful, |
17 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | * GNU Lesser General Public License for more details. |
20 | | * |
21 | | * You should have received a copy of the GNU Lesser General Public License |
22 | | * along with this program; if not, write to the Free Software Foundation, |
23 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
24 | | *****************************************************************************/ |
25 | | |
26 | | /***************************************************************************** |
27 | | * Preamble |
28 | | *****************************************************************************/ |
29 | | #ifdef HAVE_CONFIG_H |
30 | | # include "config.h" |
31 | | #endif |
32 | | |
33 | | #include <vlc_common.h> |
34 | | #include <vlc_plugin.h> |
35 | | #include <vlc_codec.h> |
36 | | |
37 | | #include <vlc_bits.h> |
38 | | |
39 | | #include "../demux/mpeg/timestamps.h" |
40 | | |
41 | | #define DEBUG_CVDSUB 1 |
42 | | |
43 | | /***************************************************************************** |
44 | | * Module descriptor. |
45 | | *****************************************************************************/ |
46 | | static int DecoderOpen ( vlc_object_t * ); |
47 | | static int PacketizerOpen( vlc_object_t * ); |
48 | | static void DecoderClose ( vlc_object_t * ); |
49 | | |
50 | 108 | vlc_module_begin () |
51 | 54 | set_description( N_("CVD subtitle decoder") ) |
52 | 54 | set_capability( "spu decoder", 50 ) |
53 | 108 | set_callbacks( DecoderOpen, DecoderClose ) |
54 | | |
55 | 54 | add_submodule () |
56 | 54 | set_description( N_("Chaoji VCD subtitle packetizer") ) |
57 | 54 | set_capability( "spu packetizer", 50 ) |
58 | 108 | set_callbacks( PacketizerOpen, DecoderClose ) |
59 | 54 | vlc_module_end () |
60 | | |
61 | | /***************************************************************************** |
62 | | * Local prototypes |
63 | | *****************************************************************************/ |
64 | | static int Decode( decoder_t *, block_t * ); |
65 | | static block_t *Packetize ( decoder_t *, block_t ** ); |
66 | | static block_t *Reassemble ( decoder_t *, block_t * ); |
67 | | static void ParseMetaInfo ( decoder_t *, block_t * ); |
68 | | static void ParseHeader ( decoder_t *, block_t * ); |
69 | | static subpicture_t *DecodePacket( decoder_t *, block_t * ); |
70 | | static void RenderImage( decoder_t *, block_t *, picture_t * ); |
71 | | |
72 | 28.3k | #define SUBTITLE_BLOCK_EMPTY 0 |
73 | 2.16k | #define SUBTITLE_BLOCK_PARTIAL 1 |
74 | | #define SUBTITLE_BLOCK_COMPLETE 2 |
75 | | |
76 | | typedef struct |
77 | | { |
78 | | int b_packetizer; |
79 | | |
80 | | int i_state; /* data-gathering state for this subtitle */ |
81 | | |
82 | | block_t *p_spu; /* Bytes of the packet. */ |
83 | | |
84 | | size_t i_spu_size; /* goal for subtitle_data_pos while gathering, |
85 | | size of used subtitle_data later */ |
86 | | |
87 | | uint16_t i_image_offset; /* offset from subtitle_data to compressed |
88 | | image data */ |
89 | | size_t first_field_offset; /* offset of even raster lines */ |
90 | | size_t second_field_offset; /* offset of odd raster lines */ |
91 | | size_t metadata_offset; /* offset to data describing the image */ |
92 | | size_t metadata_length; /* length of metadata */ |
93 | | |
94 | | vlc_tick_t i_duration; /* how long to display the image, 0 stands |
95 | | for "until next subtitle" */ |
96 | | |
97 | | uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of |
98 | | image when displayed */ |
99 | | uint16_t i_width, i_height; /* dimensions in pixels of image */ |
100 | | |
101 | | uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */ |
102 | | uint8_t p_palette_highlight[4][4]; |
103 | | } decoder_sys_t; |
104 | | |
105 | | static int OpenCommon( vlc_object_t *p_this, bool b_packetizer ) |
106 | 28.8k | { |
107 | 28.8k | decoder_t *p_dec = (decoder_t*)p_this; |
108 | 28.8k | decoder_sys_t *p_sys; |
109 | | |
110 | 28.8k | if( p_dec->fmt_in->i_codec != VLC_CODEC_CVD ) |
111 | 28.2k | return VLC_EGENERIC; |
112 | | |
113 | 560 | p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); |
114 | 560 | if( !p_sys ) |
115 | 0 | return VLC_ENOMEM; |
116 | | |
117 | 560 | p_sys->b_packetizer = b_packetizer; |
118 | | |
119 | 560 | p_sys->i_state = SUBTITLE_BLOCK_EMPTY; |
120 | 560 | p_sys->p_spu = NULL; |
121 | | |
122 | 560 | if( b_packetizer ) |
123 | 280 | { |
124 | 280 | p_dec->pf_packetize = Packetize; |
125 | 280 | p_dec->fmt_out.i_codec = VLC_CODEC_CVD; |
126 | 280 | } |
127 | 280 | else |
128 | 280 | { |
129 | 280 | p_dec->pf_decode = Decode; |
130 | 280 | p_dec->fmt_out.i_codec = VLC_CODEC_YUVP; |
131 | 280 | } |
132 | | |
133 | 560 | return VLC_SUCCESS; |
134 | 560 | } |
135 | | /***************************************************************************** |
136 | | * DecoderOpen: open/initialize the cvdsub decoder. |
137 | | *****************************************************************************/ |
138 | | static int DecoderOpen( vlc_object_t *p_this ) |
139 | 12.9k | { |
140 | 12.9k | return OpenCommon( p_this, false ); |
141 | 12.9k | } |
142 | | |
143 | | /***************************************************************************** |
144 | | * PacketizerOpen: open/initialize the cvdsub packetizer. |
145 | | *****************************************************************************/ |
146 | | static int PacketizerOpen( vlc_object_t *p_this ) |
147 | 15.8k | { |
148 | 15.8k | return OpenCommon( p_this, true ); |
149 | 15.8k | } |
150 | | |
151 | | /***************************************************************************** |
152 | | * DecoderClose: closes the cvdsub decoder/packetizer. |
153 | | *****************************************************************************/ |
154 | | void DecoderClose( vlc_object_t *p_this ) |
155 | 560 | { |
156 | 560 | decoder_t *p_dec = (decoder_t*)p_this; |
157 | 560 | decoder_sys_t *p_sys = p_dec->p_sys; |
158 | | |
159 | 560 | if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu ); |
160 | 560 | free( p_sys ); |
161 | 560 | } |
162 | | |
163 | | /***************************************************************************** |
164 | | * Decode: |
165 | | *****************************************************************************/ |
166 | | static int Decode( decoder_t *p_dec, block_t *p_block ) |
167 | 10.5k | { |
168 | 10.5k | block_t *p_data; |
169 | | |
170 | 10.5k | if( p_block == NULL ) /* No Drain */ |
171 | 9.19k | return VLCDEC_SUCCESS; |
172 | | |
173 | 1.38k | if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) |
174 | 0 | { |
175 | 0 | block_Release( p_block ); |
176 | 0 | return VLCDEC_SUCCESS; |
177 | 0 | } |
178 | | |
179 | 1.38k | if( !(p_data = Reassemble( p_dec, p_block )) ) |
180 | 287 | return VLCDEC_SUCCESS; |
181 | | |
182 | | /* Parse and decode */ |
183 | 1.10k | subpicture_t *p_spu = DecodePacket( p_dec, p_data ); |
184 | 1.10k | block_Release( p_data ); |
185 | 1.10k | if( p_spu != NULL ) |
186 | 1.09k | decoder_QueueSub( p_dec, p_spu ); |
187 | 1.10k | return VLCDEC_SUCCESS; |
188 | 1.38k | } |
189 | | |
190 | | /***************************************************************************** |
191 | | * Packetize: |
192 | | *****************************************************************************/ |
193 | | static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) |
194 | 10.5k | { |
195 | 10.5k | block_t *p_block, *p_spu; |
196 | | |
197 | 10.5k | if( pp_block == NULL || *pp_block == NULL ) return NULL; |
198 | | |
199 | 8.91k | p_block = *pp_block; |
200 | 8.91k | *pp_block = NULL; |
201 | | |
202 | 8.91k | if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL; |
203 | | |
204 | 1.38k | p_spu->i_dts = p_spu->i_pts; |
205 | 1.38k | p_spu->i_length = VLC_TICK_INVALID; |
206 | | |
207 | 1.38k | return p_spu; |
208 | 8.91k | } |
209 | | |
210 | | |
211 | | /***************************************************************************** |
212 | | Reassemble: |
213 | | |
214 | | Data for single screen subtitle may come in several non-contiguous |
215 | | packets of a stream. This routine is called when the next packet in |
216 | | the stream comes in. The job of this routine is to parse the header, |
217 | | if this is the beginning, and combine the packets into one complete |
218 | | subtitle unit. |
219 | | |
220 | | If everything is complete, we will return a block. Otherwise return |
221 | | NULL. |
222 | | |
223 | | *****************************************************************************/ |
224 | 19.6k | #define SPU_HEADER_LEN 1 |
225 | | |
226 | | static block_t *Reassemble( decoder_t *p_dec, block_t *p_block ) |
227 | 10.3k | { |
228 | 10.3k | decoder_sys_t *p_sys = p_dec->p_sys; |
229 | | |
230 | 10.3k | if( p_block->i_buffer < SPU_HEADER_LEN ) |
231 | 0 | { |
232 | 0 | msg_Dbg( p_dec, "invalid packet header (size %zu < %u)" , |
233 | 0 | p_block->i_buffer, SPU_HEADER_LEN ); |
234 | 0 | block_Release( p_block ); |
235 | 0 | return NULL; |
236 | 0 | } |
237 | | |
238 | | /* From the scant data on the format, there is only only way known |
239 | | * to detect the first packet in a subtitle. The first packet |
240 | | * seems to have a valid PTS while later packets for the same |
241 | | * image don't. */ |
242 | 10.3k | if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == VLC_TICK_INVALID ) |
243 | 5.65k | { |
244 | 5.65k | msg_Warn( p_dec, "first packet expected but no PTS present"); |
245 | 5.65k | block_Release( p_block ); |
246 | 5.65k | return NULL; |
247 | 5.65k | } |
248 | | |
249 | 4.64k | p_block->p_buffer += SPU_HEADER_LEN; |
250 | 4.64k | p_block->i_buffer -= SPU_HEADER_LEN; |
251 | | |
252 | | /* First packet in the subtitle block */ |
253 | 4.64k | if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) ParseHeader( p_dec, p_block ); |
254 | | |
255 | 4.64k | block_ChainAppend( &p_sys->p_spu, p_block ); |
256 | 4.64k | p_sys->p_spu = block_ChainGather( p_sys->p_spu ); |
257 | | |
258 | 4.64k | if( p_sys->p_spu->i_buffer >= p_sys->i_spu_size ) |
259 | 2.48k | { |
260 | 2.48k | block_t *p_spu = p_sys->p_spu; |
261 | | |
262 | 2.48k | if( p_spu->i_buffer != p_sys->i_spu_size ) |
263 | 2.45k | { |
264 | 2.45k | msg_Warn( p_dec, "SPU packets size=%zu should be %zu", |
265 | 2.45k | p_spu->i_buffer, p_sys->i_spu_size ); |
266 | 2.45k | } |
267 | | |
268 | 2.48k | msg_Dbg( p_dec, "subtitle packet complete, size=%zuu", p_spu->i_buffer); |
269 | | |
270 | 2.48k | ParseMetaInfo( p_dec, p_spu ); |
271 | | |
272 | 2.48k | p_sys->i_state = SUBTITLE_BLOCK_EMPTY; |
273 | 2.48k | p_sys->p_spu = 0; |
274 | 2.48k | return p_spu; |
275 | 2.48k | } |
276 | 2.16k | else |
277 | 2.16k | { |
278 | | /* Not last block in subtitle, so wait for another. */ |
279 | 2.16k | p_sys->i_state = SUBTITLE_BLOCK_PARTIAL; |
280 | 2.16k | } |
281 | | |
282 | 2.16k | return NULL; |
283 | 4.64k | } |
284 | | |
285 | | /* |
286 | | We do not have information on the subtitle format used on CVD's |
287 | | except the submux sample code and a couple of samples of dubious |
288 | | origin. Thus, this is the result of reading some code whose |
289 | | correctness is not known and some experimentation. |
290 | | |
291 | | CVD subtitles are different in several ways from SVCD OGT subtitles. |
292 | | Image comes first and metadata is at the end. So that the metadata |
293 | | can be found easily, the subtitle packet starts with two bytes |
294 | | (everything is big-endian again) that give the total size of the |
295 | | subtitle data and the offset to the metadata - i.e. size of the |
296 | | image data plus the four bytes at the beginning. |
297 | | |
298 | | Image data comes interlaced is run-length encoded. Each field is a |
299 | | four-bit nibble. Each nibble contains a two-bit repeat count and a |
300 | | two-bit color number so that up to three pixels can be described in |
301 | | four bits. The function of a 0 repeat count is unknown; it might be |
302 | | used for RLE extension. However when the full nibble is zero, the |
303 | | rest of the line is filled with the color value in the next nibble. |
304 | | It is unknown what happens if the color value is greater than three. |
305 | | The rest seems to use a 4-entries palette. It is not impossible |
306 | | that the fill-line complete case above is not as described and the |
307 | | zero repeat count means fill line. The sample code never produces |
308 | | this, so it may be untested. |
309 | | */ |
310 | | |
311 | | static void ParseHeader( decoder_t *p_dec, block_t *p_block ) |
312 | 2.59k | { |
313 | 2.59k | decoder_sys_t *p_sys = p_dec->p_sys; |
314 | 2.59k | uint8_t *p = p_block->p_buffer; |
315 | | |
316 | 2.59k | p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2; |
317 | | |
318 | 2.59k | p_sys->metadata_offset = (p[0] << 8) + p[1]; p +=2; |
319 | 2.59k | if ( p_sys->i_spu_size > p_sys->metadata_offset ) |
320 | 1.51k | p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset; |
321 | 1.08k | else |
322 | 1.08k | p_sys->metadata_length = 0; // unusable metadata |
323 | | |
324 | 2.59k | p_sys->i_image_offset = 4; |
325 | | |
326 | 2.59k | #ifdef DEBUG_CVDSUB |
327 | 2.59k | msg_Dbg( p_dec, "total size: %zu metadata size: %zu", |
328 | 2.59k | p_sys->i_spu_size, p_sys->metadata_length ); |
329 | 2.59k | #endif |
330 | 2.59k | } |
331 | | |
332 | | /* |
333 | | We parse the metadata information here. |
334 | | |
335 | | Although metadata information does not have to come in a fixed field |
336 | | order, every metadata field consists of a tag byte followed by |
337 | | parameters. In all cases known, the size including tag byte is |
338 | | exactly four bytes in length. |
339 | | */ |
340 | | |
341 | 2.09k | #define ExtractXY(x, y) x = ((p[1]&0x0f)<<6) + (p[2]>>2); \ |
342 | 2.09k | y = ((p[2]&0x03)<<8) + p[3]; |
343 | | |
344 | | static void ParseMetaInfo( decoder_t *p_dec, block_t *p_spu ) |
345 | 2.48k | { |
346 | | /* Last packet in subtitle block. */ |
347 | | |
348 | 2.48k | decoder_sys_t *p_sys = p_dec->p_sys; |
349 | 2.48k | uint8_t *p = p_spu->p_buffer + p_sys->metadata_offset; |
350 | 2.48k | uint8_t *p_end = p + p_sys->metadata_length; |
351 | | |
352 | 209k | for( ; &p[3] < p_end; p += 4 ) |
353 | 207k | { |
354 | 207k | switch( p[0] ) |
355 | 207k | { |
356 | 746 | case 0x04: /* subtitle duration in 1/90000ths of a second */ |
357 | 746 | p_sys->i_duration = FROM_SCALE_NZ( (p[1]<<16) + (p[2]<<8) + p[3] ); |
358 | | |
359 | 746 | #ifdef DEBUG_CVDSUB |
360 | 746 | msg_Dbg( p_dec, "subtitle display duration %"PRIu64" ms", |
361 | 746 | MS_FROM_VLC_TICK(p_sys->i_duration) ); |
362 | 746 | #endif |
363 | 746 | break; |
364 | | |
365 | 338 | case 0x0c: /* unknown */ |
366 | 338 | #ifdef DEBUG_CVDSUB |
367 | 338 | msg_Dbg( p_dec, "subtitle command unknown " |
368 | 338 | "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8, |
369 | 338 | p[0], p[1], p[2], p[3] ); |
370 | 338 | #endif |
371 | 338 | break; |
372 | | |
373 | 945 | case 0x17: /* coordinates of subtitle upper left x, y position */ |
374 | 945 | ExtractXY(p_sys->i_x_start, p_sys->i_y_start); |
375 | | |
376 | 945 | #ifdef DEBUG_CVDSUB |
377 | 945 | msg_Dbg( p_dec, "start position (%"PRIu16",%"PRIu16")", |
378 | 945 | p_sys->i_x_start, p_sys->i_y_start ); |
379 | 945 | #endif |
380 | 945 | break; |
381 | | |
382 | 1.15k | case 0x1f: /* coordinates of subtitle bottom right x, y position */ |
383 | 1.15k | { |
384 | 1.15k | int lastx; |
385 | 1.15k | int lasty; |
386 | 1.15k | ExtractXY(lastx, lasty); |
387 | 1.15k | p_sys->i_width = lastx - p_sys->i_x_start + 1; |
388 | 1.15k | p_sys->i_height = lasty - p_sys->i_y_start + 1; |
389 | | |
390 | 1.15k | #ifdef DEBUG_CVDSUB |
391 | 1.15k | msg_Dbg( p_dec, "end position (%d,%d), w x h: %"PRIu16"x%"PRIu16, |
392 | 1.15k | lastx, lasty, p_sys->i_width, p_sys->i_height ); |
393 | 1.15k | #endif |
394 | 1.15k | break; |
395 | 0 | } |
396 | | |
397 | 3.17k | case 0x24: |
398 | 9.54k | case 0x25: |
399 | 10.0k | case 0x26: |
400 | 10.1k | case 0x27: |
401 | 10.1k | { |
402 | 10.1k | uint8_t v = p[0] - 0x24; |
403 | | |
404 | 10.1k | #ifdef DEBUG_CVDSUB |
405 | | /* Primary Palette */ |
406 | 10.1k | msg_Dbg( p_dec, "primary palette %"PRIu8" (y,u,v): " |
407 | 10.1k | "(0x%02"PRIx8",0x%02"PRIx8",0x%02"PRIx8")", |
408 | 10.1k | v, p[1], p[2], p[3] ); |
409 | 10.1k | #endif |
410 | | |
411 | 10.1k | p_sys->p_palette[v][0] = p[1]; /* Y */ |
412 | 10.1k | p_sys->p_palette[v][1] = p[2]; /* Cb / U */ |
413 | 10.1k | p_sys->p_palette[v][2] = p[3]; /* Cr / V */ |
414 | 10.1k | break; |
415 | 10.0k | } |
416 | | |
417 | 1.09k | case 0x2c: |
418 | 2.79k | case 0x2d: |
419 | 4.59k | case 0x2e: |
420 | 5.69k | case 0x2f: |
421 | 5.69k | { |
422 | 5.69k | uint8_t v = p[0] - 0x2c; |
423 | | |
424 | 5.69k | #ifdef DEBUG_CVDSUB |
425 | 5.69k | msg_Dbg( p_dec,"highlight palette %"PRIu8" (y,u,v): " |
426 | 5.69k | "(0x%02"PRIx8",0x%02"PRIx8",0x%02"PRIx8")", |
427 | 5.69k | v, p[1], p[2], p[3] ); |
428 | 5.69k | #endif |
429 | | |
430 | | /* Highlight Palette */ |
431 | 5.69k | p_sys->p_palette_highlight[v][0] = p[1]; /* Y */ |
432 | 5.69k | p_sys->p_palette_highlight[v][1] = p[2]; /* Cb / U */ |
433 | 5.69k | p_sys->p_palette_highlight[v][2] = p[3]; /* Cr / V */ |
434 | 5.69k | break; |
435 | 4.59k | } |
436 | | |
437 | 1.34k | case 0x37: |
438 | | /* transparency for primary palette */ |
439 | 1.34k | p_sys->p_palette[0][3] = (p[3] & 0x0f) << 4; |
440 | 1.34k | p_sys->p_palette[1][3] = (p[3] >> 4) << 4; |
441 | 1.34k | p_sys->p_palette[2][3] = (p[2] & 0x0f) << 4; |
442 | 1.34k | p_sys->p_palette[3][3] = (p[2] >> 4) << 4; |
443 | | |
444 | 1.34k | #ifdef DEBUG_CVDSUB |
445 | 1.34k | msg_Dbg( p_dec, "transparency for primary palette 0..3: " |
446 | 1.34k | "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8, |
447 | 1.34k | p_sys->p_palette[0][3], p_sys->p_palette[1][3], |
448 | 1.34k | p_sys->p_palette[2][3], p_sys->p_palette[3][3]); |
449 | 1.34k | #endif |
450 | 1.34k | break; |
451 | | |
452 | 752 | case 0x3f: |
453 | | /* transparency for highlight palette */ |
454 | 752 | p_sys->p_palette_highlight[0][3] = (p[2] & 0x0f) << 4; |
455 | 752 | p_sys->p_palette_highlight[1][3] = (p[2] >> 4) << 4; |
456 | 752 | p_sys->p_palette_highlight[2][3] = (p[1] & 0x0f) << 4; |
457 | 752 | p_sys->p_palette_highlight[3][3] = (p[1] >> 4) << 4; |
458 | | |
459 | 752 | #ifdef DEBUG_CVDSUB |
460 | 752 | msg_Dbg( p_dec, "transparency for highlight palette 0..3: " |
461 | 752 | "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8, |
462 | 752 | p_sys->p_palette_highlight[0][3], |
463 | 752 | p_sys->p_palette_highlight[1][3], |
464 | 752 | p_sys->p_palette_highlight[2][3], |
465 | 752 | p_sys->p_palette_highlight[3][3] ); |
466 | 752 | #endif |
467 | 752 | break; |
468 | | |
469 | 455 | case 0x47: |
470 | | /* offset to start of even rows of interlaced image, we correct |
471 | | * to make it relative to i_image_offset (usually 4) */ |
472 | 455 | p_sys->first_field_offset = |
473 | 455 | (p[2] << 8) + p[3] - p_sys->i_image_offset; |
474 | 455 | #ifdef DEBUG_CVDSUB |
475 | 455 | msg_Dbg( p_dec, "1st_field_offset %zu", |
476 | 455 | p_sys->first_field_offset ); |
477 | 455 | #endif |
478 | 455 | break; |
479 | | |
480 | 779 | case 0x4f: |
481 | | /* offset to start of odd rows of interlaced image, we correct |
482 | | * to make it relative to i_image_offset (usually 4) */ |
483 | 779 | p_sys->second_field_offset = |
484 | 779 | (p[2] << 8) + p[3] - p_sys->i_image_offset; |
485 | 779 | #ifdef DEBUG_CVDSUB |
486 | 779 | msg_Dbg( p_dec, "2nd_field_offset %zu", |
487 | 779 | p_sys->second_field_offset); |
488 | 779 | #endif |
489 | 779 | break; |
490 | | |
491 | 184k | default: |
492 | 184k | #ifdef DEBUG_CVDSUB |
493 | 184k | msg_Warn( p_dec, "unknown sequence in control header " |
494 | 207k | "0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8" 0x%02"PRIx8, |
495 | 207k | p[0], p[1], p[2], p[3]); |
496 | 207k | #endif |
497 | 207k | } |
498 | 207k | } |
499 | 2.48k | } |
500 | | |
501 | | /***************************************************************************** |
502 | | * DecodePacket: parse and decode an SPU packet |
503 | | ***************************************************************************** |
504 | | * This function parses and decodes an SPU packet and, if valid, returns a |
505 | | * subpicture. |
506 | | *****************************************************************************/ |
507 | | static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data ) |
508 | 1.10k | { |
509 | 1.10k | decoder_sys_t *p_sys = p_dec->p_sys; |
510 | 1.10k | subpicture_t *p_spu; |
511 | 1.10k | subpicture_region_t *p_region; |
512 | 1.10k | video_format_t fmt; |
513 | 1.10k | video_palette_t palette; |
514 | 1.10k | int i; |
515 | | |
516 | | /* Allocate the subpicture internal data. */ |
517 | 1.10k | p_spu = decoder_NewSubpicture( p_dec, NULL ); |
518 | 1.10k | if( !p_spu ) return NULL; |
519 | | |
520 | 1.10k | p_spu->i_start = p_data->i_pts; |
521 | 1.10k | p_spu->i_stop = p_data->i_pts + p_sys->i_duration; |
522 | 1.10k | p_spu->b_ephemer = true; |
523 | | |
524 | | /* Create new SPU region */ |
525 | 1.10k | video_format_Init( &fmt, VLC_CODEC_YUVP ); |
526 | 1.10k | fmt.i_sar_num = 1; |
527 | 1.10k | fmt.i_sar_den = 1; |
528 | 1.10k | fmt.i_width = fmt.i_visible_width = p_sys->i_width; |
529 | 1.10k | fmt.i_height = fmt.i_visible_height = p_sys->i_height; |
530 | 1.10k | fmt.i_x_offset = fmt.i_y_offset = 0; |
531 | 1.10k | fmt.p_palette = &palette; |
532 | 1.10k | fmt.p_palette->i_entries = 4; |
533 | 5.50k | for( i = 0; i < fmt.p_palette->i_entries; i++ ) |
534 | 4.40k | memcpy( fmt.p_palette->palette[i], p_sys->p_palette[i], 4 ); |
535 | | |
536 | 1.10k | p_region = subpicture_region_New( &fmt ); |
537 | 1.10k | if( !p_region ) |
538 | 10 | { |
539 | 10 | msg_Err( p_dec, "cannot allocate SPU region" ); |
540 | 10 | subpicture_Delete( p_spu ); |
541 | 10 | return NULL; |
542 | 10 | } |
543 | | |
544 | 1.09k | vlc_spu_regions_push(&p_spu->regions, p_region); |
545 | 1.09k | p_region->b_absolute = true; p_region->b_in_window = false; |
546 | 1.09k | p_region->i_x = p_sys->i_x_start; |
547 | 1.09k | p_region->i_x = p_region->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */ |
548 | 1.09k | p_region->i_y = p_sys->i_y_start; |
549 | | |
550 | 1.09k | RenderImage( p_dec, p_data, p_region->p_picture ); |
551 | | |
552 | 1.09k | return p_spu; |
553 | 1.10k | } |
554 | | |
555 | | /***************************************************************************** |
556 | | * ParseImage: parse and render the image part of the subtitle |
557 | | ***************************************************************************** |
558 | | This part parses the subtitle graphical data and renders it. |
559 | | |
560 | | Image data comes interlaced and is run-length encoded (RLE). Each |
561 | | field is a four-bit nibbles that is further subdivided in a two-bit |
562 | | repeat count and a two-bit color number - up to three pixels can be |
563 | | described in four bits. What a 0 repeat count means is unknown. It |
564 | | might be used for RLE extension. There is a special case of a 0 |
565 | | repeat count though. When the full nibble is zero, the rest of the |
566 | | line is filled with the color value in the next nibble. It is |
567 | | unknown what happens if the color value is greater than three. The |
568 | | rest seems to use a 4-entries palette. It is not impossible that the |
569 | | fill-line complete case above is not as described and the zero repeat |
570 | | count means fill line. The sample code never produces this, so it |
571 | | may be untested. |
572 | | |
573 | | However we'll transform this so that that the RLE is expanded and |
574 | | interlacing will also be removed. On output each pixel entry will by |
575 | | a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry. |
576 | | |
577 | | *****************************************************************************/ |
578 | | static void RenderImage( decoder_t *p_dec, block_t *p_data, |
579 | | picture_t *dst_pic ) |
580 | 1.09k | { |
581 | 1.09k | decoder_sys_t *p_sys = p_dec->p_sys; |
582 | 1.09k | uint8_t *p_dest = dst_pic->Y_PIXELS; |
583 | 1.09k | int i_field; /* The subtitles are interlaced */ |
584 | 1.09k | int i_row, i_column; /* scanline row/column number */ |
585 | 1.09k | uint8_t i_color, i_count; |
586 | 1.09k | bs_t bs; |
587 | | |
588 | 1.09k | bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset, |
589 | 1.09k | p_data->i_buffer - p_sys->i_image_offset ); |
590 | | |
591 | 3.27k | for( i_field = 0; i_field < 2; i_field++ ) |
592 | 2.18k | { |
593 | 709k | for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 ) |
594 | 707k | { |
595 | 1.60M | for( i_column = 0; i_column < p_sys->i_width; i_column++ ) |
596 | 895k | { |
597 | 895k | uint8_t i_val = bs_read( &bs, 4 ); |
598 | | |
599 | 895k | if( i_val == 0 ) |
600 | 628k | { |
601 | | /* Fill the rest of the line with next color */ |
602 | 628k | i_color = bs_read( &bs, 4 ); |
603 | | |
604 | 628k | memset( &p_dest[i_row * dst_pic->Y_PITCH + |
605 | 628k | i_column], i_color, |
606 | 628k | p_sys->i_width - i_column ); |
607 | 628k | i_column = p_sys->i_width; |
608 | 628k | continue; |
609 | 628k | } |
610 | 266k | else |
611 | 266k | { |
612 | | /* Normal case: get color and repeat count */ |
613 | 266k | i_count = (i_val >> 2); |
614 | 266k | i_color = i_val & 0x3; |
615 | | |
616 | 266k | i_count = __MIN( i_count, p_sys->i_width - i_column ); |
617 | | |
618 | 266k | memset( &p_dest[i_row * dst_pic->Y_PITCH + |
619 | 266k | i_column], i_color, i_count ); |
620 | 266k | i_column += i_count - 1; |
621 | 266k | continue; |
622 | 266k | } |
623 | 895k | } |
624 | | |
625 | 707k | bs_align( &bs ); |
626 | 707k | } |
627 | 2.18k | } |
628 | 1.09k | } |