/src/vlc/modules/codec/dvbsub.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * dvbsub.c : DVB subtitles decoder |
3 | | * DVB subtitles encoder (developed for Anevia, www.anevia.com) |
4 | | ***************************************************************************** |
5 | | * Copyright (C) 2003 ANEVIA |
6 | | * Copyright (C) 2003-2009 VLC authors and VideoLAN |
7 | | * |
8 | | * Authors: Gildas Bazin <gbazin@videolan.org> |
9 | | * Damien LUCAS <damien.lucas@anevia.com> |
10 | | * Laurent Aimar <fenrir@via.ecp.fr> |
11 | | * Jean-Paul Saman <jpsaman #_at_# m2x dot nl> |
12 | | * Derk-Jan Hartman <hartman #at# videolan dot org> |
13 | | * Simon Hailes <simon _a_ screen.subtitling.com> |
14 | | * |
15 | | * This program is free software; you can redistribute it and/or modify it |
16 | | * under the terms of the GNU Lesser General Public License as published by |
17 | | * the Free Software Foundation; either version 2.1 of the License, or |
18 | | * (at your option) any later version. |
19 | | * |
20 | | * This program is distributed in the hope that it will be useful, |
21 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | | * GNU Lesser General Public License for more details. |
24 | | * |
25 | | * You should have received a copy of the GNU Lesser General Public License |
26 | | * along with this program; if not, write to the Free Software Foundation, Inc., |
27 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
28 | | *****************************************************************************/ |
29 | | |
30 | | /***************************************************************************** |
31 | | * Preamble |
32 | | * |
33 | | * FIXME: |
34 | | * DVB subtitles coded as strings of characters are not handled correctly. |
35 | | * The character codes in the string should actually be indexes referring to a |
36 | | * character table identified in the subtitle descriptor. |
37 | | * |
38 | | * The spec is quite vague in this area, but what is meant is perhaps that it |
39 | | * refers to the character index in the codepage belonging to the language |
40 | | * specified in the subtitle descriptor. Potentially it's designed for widechar |
41 | | * (but not for UTF-*) codepages. |
42 | | ***************************************************************************** |
43 | | * |
44 | | ***************************************************************************** |
45 | | * Notes on DDS (Display Definition Segment) |
46 | | * ----------------------------------------- |
47 | | * DDS (Display Definition Segment) tells the decoder how the subtitle image |
48 | | * relates to the video image. |
49 | | * For SD, the subtitle image is always considered to be for display at |
50 | | * 720x576 (although it's assumed that for NTSC, this is 720x480, this |
51 | | * is not documented well) Also, for SD, the subtitle image is drawn 'on |
52 | | * the glass' (i.e. after video scaling, letterbox, etc.) |
53 | | * For 'HD' (subs marked type 0x14/0x24 in PSI), a DDS must be present, |
54 | | * and the subs area is drawn onto the video area (scales if necessary). |
55 | | * The DDS tells the decoder what resolution the subtitle images were |
56 | | * intended for, and hence how to scale the subtitle images for a |
57 | | * particular video size |
58 | | * i.e. if HD video is presented as letterbox, the subs will be in the |
59 | | * same place on the video as if the video was presented on an HD set |
60 | | * indeed, if the HD video was pillarboxed by the decoder, the subs may |
61 | | * be cut off as well as the video. The intent here is that the subs can |
62 | | * be placed accurately on the video - something which was missed in the |
63 | | * original spec. |
64 | | * |
65 | | * A DDS may also specify a window - this is where the subs images are moved so that the (0,0) |
66 | | * origin of decode is offset. |
67 | | ********************************************************************************************/ |
68 | | |
69 | | #ifdef HAVE_CONFIG_H |
70 | | # include "config.h" |
71 | | #endif |
72 | | |
73 | | #include <vlc_common.h> |
74 | | #include <vlc_configuration.h> |
75 | | #include <vlc_plugin.h> |
76 | | #include <vlc_codec.h> |
77 | | #include <vlc_sout.h> |
78 | | #include <vlc_arrays.h> |
79 | | |
80 | | #include <vlc_bits.h> |
81 | | |
82 | | #include <limits.h> |
83 | | #include <stdckdint.h> |
84 | | |
85 | | /* #define DEBUG_DVBSUB 1 */ |
86 | | |
87 | | #define POSX_TEXT N_("Decoding X coordinate") |
88 | | #define POSX_LONGTEXT N_("X coordinate of the rendered subtitle") |
89 | | |
90 | | #define POSY_TEXT N_("Decoding Y coordinate") |
91 | | #define POSY_LONGTEXT N_("Y coordinate of the rendered subtitle") |
92 | | |
93 | | #define POS_TEXT N_("Subpicture position") |
94 | | #define POS_LONGTEXT N_( \ |
95 | | "You can enforce the subpicture position on the video " \ |
96 | | "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \ |
97 | | "also use combinations of these values, e.g. 6=top-right).") |
98 | | |
99 | | #define ENC_POSX_TEXT N_("Encoding X coordinate") |
100 | | #define ENC_POSX_LONGTEXT N_("X coordinate of the encoded subtitle" ) |
101 | | #define ENC_POSY_TEXT N_("Encoding Y coordinate") |
102 | | #define ENC_POSY_LONGTEXT N_("Y coordinate of the encoded subtitle" ) |
103 | | |
104 | | static const int pi_pos_values[] = { |
105 | | 0, |
106 | | SUBPICTURE_ALIGN_LEFT, |
107 | | SUBPICTURE_ALIGN_RIGHT, |
108 | | SUBPICTURE_ALIGN_TOP, |
109 | | SUBPICTURE_ALIGN_BOTTOM, |
110 | | SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT, |
111 | | SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT, |
112 | | SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT, |
113 | | SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT, |
114 | | }; |
115 | | static const char *const ppsz_pos_descriptions[] = |
116 | | { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"), |
117 | | N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") }; |
118 | | |
119 | | /***************************************************************************** |
120 | | * Module descriptor. |
121 | | *****************************************************************************/ |
122 | | static int Open ( vlc_object_t * ); |
123 | | static void Close( vlc_object_t * ); |
124 | | static int Decode( decoder_t *, block_t * ); |
125 | | static void Flush( decoder_t * ); |
126 | | |
127 | | #ifdef ENABLE_SOUT |
128 | | static int OpenEncoder ( vlc_object_t * ); |
129 | | static void CloseEncoder( encoder_t * ); |
130 | | static block_t *Encode ( encoder_t *, subpicture_t * ); |
131 | | #endif |
132 | | |
133 | 138 | vlc_module_begin () |
134 | 69 | # define DVBSUB_CFG_PREFIX "dvbsub-" |
135 | 69 | set_description( N_("DVB subtitles decoder") ) |
136 | 69 | set_shortname( N_("DVB subtitles") ) |
137 | 69 | set_capability( "spu decoder", 80 ) |
138 | 69 | set_subcategory( SUBCAT_INPUT_SCODEC ) |
139 | 69 | set_callbacks( Open, Close ) |
140 | | |
141 | 69 | add_integer( DVBSUB_CFG_PREFIX "position", 8, POS_TEXT, POS_LONGTEXT ) |
142 | 69 | change_integer_list( pi_pos_values, ppsz_pos_descriptions ) |
143 | 69 | add_integer( DVBSUB_CFG_PREFIX "x", -1, POSX_TEXT, POSX_LONGTEXT ) |
144 | 69 | add_integer( DVBSUB_CFG_PREFIX "y", -1, POSY_TEXT, POSY_LONGTEXT ) |
145 | | |
146 | 69 | #ifdef ENABLE_SOUT |
147 | 69 | # define ENC_CFG_PREFIX "sout-dvbsub-" |
148 | 69 | add_submodule () |
149 | 69 | set_description( N_("DVB subtitles encoder") ) |
150 | 69 | set_capability( "spu encoder", 100 ) |
151 | 69 | set_callback( OpenEncoder ) |
152 | | |
153 | 69 | add_integer( ENC_CFG_PREFIX "x", -1, ENC_POSX_TEXT, ENC_POSX_LONGTEXT ) |
154 | 69 | add_integer( ENC_CFG_PREFIX "y", -1, ENC_POSY_TEXT, ENC_POSY_LONGTEXT ) |
155 | 69 | #endif |
156 | 69 | vlc_module_end () |
157 | | |
158 | | static const char *const ppsz_enc_options[] = { "x", "y", NULL }; |
159 | | |
160 | | /**************************************************************************** |
161 | | * Local structures |
162 | | **************************************************************************** |
163 | | * Those structures refer closely to the ETSI 300 743 Object model |
164 | | ****************************************************************************/ |
165 | | |
166 | | /* The object definition gives the position of the object in a region [7.2.5] */ |
167 | | typedef struct dvbsub_objectdef_s |
168 | | { |
169 | | int i_id; |
170 | | int i_type; |
171 | | int i_x; |
172 | | int i_y; |
173 | | int i_fg_pc; |
174 | | int i_bg_pc; |
175 | | char *psz_text; /* for string of characters objects */ |
176 | | |
177 | | } dvbsub_objectdef_t; |
178 | | |
179 | | /* The entry in the palette CLUT */ |
180 | | typedef struct |
181 | | { |
182 | | uint8_t Y; |
183 | | uint8_t Cr; |
184 | | uint8_t Cb; |
185 | | uint8_t T; |
186 | | |
187 | | } dvbsub_color_t; |
188 | | |
189 | | /* The displays dimensions [7.2.1] */ |
190 | | typedef struct dvbsub_display_s |
191 | | { |
192 | | uint8_t i_id; |
193 | | uint8_t i_version; |
194 | | |
195 | | uint16_t i_width_minus1; |
196 | | uint16_t i_height_minus1; |
197 | | |
198 | | bool b_windowed; |
199 | | /* these values are only relevant if windowed */ |
200 | | int i_x; |
201 | | int i_y; |
202 | | int i_max_x; |
203 | | int i_max_y; |
204 | | |
205 | | } dvbsub_display_t; |
206 | | |
207 | | /* [7.2.4] */ |
208 | | typedef struct dvbsub_clut_s |
209 | | { |
210 | | uint8_t i_id; |
211 | | uint8_t i_version; |
212 | | dvbsub_color_t c_2b[4]; |
213 | | dvbsub_color_t c_4b[16]; |
214 | | dvbsub_color_t c_8b[256]; |
215 | | int c_8b_entries; |
216 | | video_color_range_t color_range; |
217 | | int dynamic_range_and_colour_gamut; |
218 | | |
219 | | struct dvbsub_clut_s *p_next; |
220 | | |
221 | | } dvbsub_clut_t; |
222 | | |
223 | | /* The Region is an area on the image [7.2.3] |
224 | | * with a list of the object definitions associated and a CLUT */ |
225 | | typedef struct dvbsub_region_s |
226 | | { |
227 | | int i_id; |
228 | | int i_version; |
229 | | int i_x; |
230 | | int i_y; |
231 | | int i_width; |
232 | | int i_height; |
233 | | int i_level_comp; |
234 | | int i_depth; |
235 | | int i_clut; |
236 | | |
237 | | uint8_t *p_pixbuf; |
238 | | |
239 | | int i_object_defs; |
240 | | dvbsub_objectdef_t *p_object_defs; |
241 | | |
242 | | struct dvbsub_region_s *p_next; |
243 | | |
244 | | } dvbsub_region_t; |
245 | | |
246 | | /* The object definition gives the position of the object in a region */ |
247 | | typedef struct dvbsub_regiondef_s |
248 | | { |
249 | | int i_id; |
250 | | int i_x; |
251 | | int i_y; |
252 | | |
253 | | } dvbsub_regiondef_t; |
254 | | |
255 | | /* The page defines the list of regions [7.2.2] */ |
256 | | typedef struct |
257 | | { |
258 | | int i_id; |
259 | | int i_timeout; /* in seconds */ |
260 | | int i_state; |
261 | | int i_version; |
262 | | |
263 | | int i_region_defs; |
264 | | dvbsub_regiondef_t *p_region_defs; |
265 | | |
266 | | } dvbsub_page_t; |
267 | | |
268 | | typedef struct |
269 | | { |
270 | | bs_t bs; |
271 | | |
272 | | /* Decoder internal data */ |
273 | | int i_id; |
274 | | int i_ancillary_id; |
275 | | vlc_tick_t i_pts; |
276 | | |
277 | | int i_spu_position; |
278 | | int i_spu_x; |
279 | | int i_spu_y; |
280 | | |
281 | | bool b_page; |
282 | | dvbsub_page_t *p_page; |
283 | | dvbsub_region_t *p_regions; |
284 | | dvbsub_clut_t *p_cluts; |
285 | | /* this is very small, so keep forever */ |
286 | | dvbsub_display_t display; |
287 | | dvbsub_clut_t default_clut; |
288 | | } decoder_sys_t; |
289 | | |
290 | | |
291 | | /* List of different SEGMENT TYPES */ |
292 | | /* According to EN 300-743, table 2 */ |
293 | 478 | #define DVBSUB_ST_PAGE_COMPOSITION 0x10 |
294 | 424 | #define DVBSUB_ST_REGION_COMPOSITION 0x11 |
295 | 337 | #define DVBSUB_ST_CLUT_DEFINITION 0x12 |
296 | 488 | #define DVBSUB_ST_OBJECT_DATA 0x13 |
297 | 476 | #define DVBSUB_ST_DISPLAY_DEFINITION 0x14 |
298 | 212 | #define DVBSUB_ST_ALTERNATE_CLUT 0x16 |
299 | 109 | #define DVBSUB_ST_ENDOFDISPLAY 0x80 |
300 | 116 | #define DVBSUB_ST_STUFFING 0xff |
301 | | /* List of different OBJECT TYPES */ |
302 | | /* According to EN 300-743, table 6 */ |
303 | 0 | #define DVBSUB_OT_BASIC_BITMAP 0x00 |
304 | 236k | #define DVBSUB_OT_BASIC_CHAR 0x01 |
305 | 236k | #define DVBSUB_OT_COMPOSITE_STRING 0x02 |
306 | | /* Pixel DATA TYPES */ |
307 | | /* According to EN 300-743, table 9 */ |
308 | | #define DVBSUB_DT_2BP_CODE_STRING 0x10 |
309 | | #define DVBSUB_DT_4BP_CODE_STRING 0x11 |
310 | | #define DVBSUB_DT_8BP_CODE_STRING 0x12 |
311 | | #define DVBSUB_DT_24_TABLE_DATA 0x20 |
312 | | #define DVBSUB_DT_28_TABLE_DATA 0x21 |
313 | | #define DVBSUB_DT_48_TABLE_DATA 0x22 |
314 | | #define DVBSUB_DT_END_LINE 0xf0 |
315 | | /* List of different Page Composition Segment state */ |
316 | | /* According to EN 300-743, 7.2.1 table 3 */ |
317 | 206 | #define DVBSUB_PCS_STATE_ACQUISITION 0x01 |
318 | 544 | #define DVBSUB_PCS_STATE_CHANGE 0x02 |
319 | | /* According to EN 300-743, 7.2.8 table 33 */ |
320 | 284 | #define DVBSUB_ST_BITDEPTH_8BIT 0x00 |
321 | 4.65k | #define DVBSUB_ST_BITDEPTH_10BIT 0x01 |
322 | | /* According to EN 300-743, 7.2.8 table 34 */ |
323 | 1.35k | #define DVBSUB_ST_COLORIMETRY_CDS -1 |
324 | 0 | #define DVBSUB_ST_COLORIMETRY_SDR_709 0x00 |
325 | 0 | #define DVBSUB_ST_COLORIMETRY_SDR_2020 0x01 |
326 | 0 | #define DVBSUB_ST_COLORIMETRY_HDR_PQ 0x02 |
327 | 142 | #define DVBSUB_ST_COLORIMETRY_HDR_HLG 0x03 |
328 | | |
329 | | /***************************************************************************** |
330 | | * Local prototypes |
331 | | *****************************************************************************/ |
332 | | static void decode_segment( decoder_t *, bs_t * ); |
333 | | static void decode_page_composition( decoder_t *, bs_t *, uint16_t ); |
334 | | static void decode_region_composition( decoder_t *, bs_t *, uint16_t ); |
335 | | static void decode_object( decoder_t *, bs_t *, uint16_t ); |
336 | | static void decode_display_definition( decoder_t *, bs_t *, uint16_t ); |
337 | | static void alternative_CLUT( decoder_t *, bs_t *, uint16_t ); |
338 | | static void decode_clut( decoder_t *, bs_t *, uint16_t ); |
339 | | static void free_all( decoder_t * ); |
340 | | |
341 | | static void default_clut_init( decoder_t * ); |
342 | | static void default_dds_init( decoder_t * ); |
343 | | |
344 | | static subpicture_t *render( decoder_t * ); |
345 | | |
346 | | /***************************************************************************** |
347 | | * Open: probe the decoder and return score |
348 | | ***************************************************************************** |
349 | | * Tries to launch a decoder and return score so that the interface is able |
350 | | * to chose. |
351 | | *****************************************************************************/ |
352 | | static int Open( vlc_object_t *p_this ) |
353 | 19.9k | { |
354 | 19.9k | decoder_t *p_dec = (decoder_t *) p_this; |
355 | 19.9k | decoder_sys_t *p_sys; |
356 | 19.9k | int i_posx, i_posy; |
357 | | |
358 | 19.9k | if( p_dec->fmt_in->i_codec != VLC_CODEC_DVBS ) |
359 | 18.5k | { |
360 | 18.5k | return VLC_EGENERIC; |
361 | 18.5k | } |
362 | | |
363 | 1.31k | p_dec->pf_decode = Decode; |
364 | 1.31k | p_dec->pf_flush = Flush; |
365 | 1.31k | p_sys = p_dec->p_sys = calloc( 1, sizeof(decoder_sys_t) ); |
366 | 1.31k | if( !p_sys ) |
367 | 0 | return VLC_ENOMEM; |
368 | | |
369 | 1.31k | p_sys->i_pts = VLC_TICK_INVALID; |
370 | 1.31k | p_sys->i_id = p_dec->fmt_in->subs.dvb.i_id & 0xFFFF; |
371 | 1.31k | p_sys->i_ancillary_id = p_dec->fmt_in->subs.dvb.i_id >> 16; |
372 | | |
373 | 1.31k | p_sys->p_regions = NULL; |
374 | 1.31k | p_sys->p_cluts = NULL; |
375 | 1.31k | p_sys->p_page = NULL; |
376 | | |
377 | | /* configure for SD res in case DDS is not present */ |
378 | 1.31k | default_dds_init( p_dec ); |
379 | | |
380 | 1.31k | p_sys->i_spu_position = var_CreateGetInteger( p_this, |
381 | 1.31k | DVBSUB_CFG_PREFIX "position" ); |
382 | 1.31k | i_posx = var_CreateGetInteger( p_this, DVBSUB_CFG_PREFIX "x" ); |
383 | 1.31k | i_posy = var_CreateGetInteger( p_this, DVBSUB_CFG_PREFIX "y" ); |
384 | | |
385 | | /* Check if subpicture position was overridden */ |
386 | 1.31k | p_sys->i_spu_x = p_sys->i_spu_y = 0; |
387 | | |
388 | 1.31k | if( ( i_posx >= 0 ) && ( i_posy >= 0 ) ) |
389 | 0 | { |
390 | 0 | p_sys->i_spu_x = i_posx; |
391 | 0 | p_sys->i_spu_y = i_posy; |
392 | 0 | } |
393 | | |
394 | 1.31k | p_dec->fmt_out.i_codec = 0; |
395 | | |
396 | 1.31k | default_clut_init( p_dec ); |
397 | | |
398 | 1.31k | return VLC_SUCCESS; |
399 | 1.31k | } |
400 | | |
401 | | /***************************************************************************** |
402 | | * Close: |
403 | | *****************************************************************************/ |
404 | | static void Close( vlc_object_t *p_this ) |
405 | 1.31k | { |
406 | 1.31k | decoder_t *p_dec = (decoder_t*) p_this; |
407 | 1.31k | decoder_sys_t *p_sys = p_dec->p_sys; |
408 | | |
409 | 1.31k | var_Destroy( p_this, DVBSUB_CFG_PREFIX "x" ); |
410 | 1.31k | var_Destroy( p_this, DVBSUB_CFG_PREFIX "y" ); |
411 | 1.31k | var_Destroy( p_this, DVBSUB_CFG_PREFIX "position" ); |
412 | | |
413 | 1.31k | free_all( p_dec ); |
414 | 1.31k | free( p_sys ); |
415 | 1.31k | } |
416 | | |
417 | | /***************************************************************************** |
418 | | * Flush: |
419 | | *****************************************************************************/ |
420 | | static void Flush( decoder_t *p_dec ) |
421 | 0 | { |
422 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
423 | |
|
424 | 0 | p_sys->i_pts = VLC_TICK_INVALID; |
425 | 0 | } |
426 | | |
427 | | /***************************************************************************** |
428 | | * Decode: |
429 | | *****************************************************************************/ |
430 | | static int Decode( decoder_t *p_dec, block_t *p_block ) |
431 | 2.65k | { |
432 | 2.65k | decoder_sys_t *p_sys = p_dec->p_sys; |
433 | | |
434 | 2.65k | if( p_block == NULL ) /* No Drain */ |
435 | 1.99k | return VLCDEC_SUCCESS; |
436 | | |
437 | 668 | if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) ) |
438 | 0 | { |
439 | 0 | Flush( p_dec ); |
440 | 0 | if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) |
441 | 0 | goto end; |
442 | 0 | } |
443 | | |
444 | | /* configure for SD res in case DDS is not present */ |
445 | | /* a change of PTS is a good indication we must get a new DDS */ |
446 | 668 | if( p_sys->i_pts != p_block->i_pts ) |
447 | 641 | default_dds_init( p_dec ); |
448 | | |
449 | 668 | p_sys->i_pts = p_block->i_pts; |
450 | 668 | if( p_sys->i_pts == VLC_TICK_INVALID ) |
451 | 0 | { |
452 | | #ifdef DEBUG_DVBSUB |
453 | | /* Some DVB channels send stuffing segments in non-dated packets so |
454 | | * don't complain too loudly. */ |
455 | | msg_Warn( p_dec, "non dated subtitle" ); |
456 | | #endif |
457 | 0 | goto end; |
458 | 0 | } |
459 | | |
460 | 668 | bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer ); |
461 | | |
462 | 668 | if( bs_read( &p_sys->bs, 8 ) != 0x20 ) /* Data identifier */ |
463 | 27 | { |
464 | 27 | msg_Dbg( p_dec, "invalid data identifier" ); |
465 | 27 | goto end; |
466 | 27 | } |
467 | | |
468 | 641 | if( bs_read( &p_sys->bs, 8 ) ) /* Subtitle stream id */ |
469 | 32 | { |
470 | 32 | msg_Dbg( p_dec, "invalid subtitle stream id" ); |
471 | 32 | goto end; |
472 | 32 | } |
473 | | |
474 | | #ifdef DEBUG_DVBSUB |
475 | | msg_Dbg( p_dec, "subtitle packet received: %"PRId64, p_sys->i_pts ); |
476 | | #endif |
477 | | |
478 | 609 | p_sys->b_page = false; |
479 | | |
480 | 609 | uint8_t i_sync_byte = bs_read( &p_sys->bs, 8 ); |
481 | 3.38k | while( i_sync_byte == 0x0f ) /* Sync byte */ |
482 | 2.78k | { |
483 | 2.78k | decode_segment( p_dec, &p_sys->bs ); |
484 | 2.78k | i_sync_byte = bs_read( &p_sys->bs, 8 ); |
485 | 2.78k | } |
486 | | |
487 | 609 | if( ( i_sync_byte & 0x3f ) != 0x3f ) /* End marker */ |
488 | 437 | { |
489 | 437 | msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" ); |
490 | 437 | goto end; |
491 | 437 | } |
492 | | |
493 | | /* Check if the page is to be displayed */ |
494 | 172 | if( p_sys->p_page && p_sys->b_page ) |
495 | 106 | { |
496 | 106 | subpicture_t *p_spu = render( p_dec ); |
497 | 106 | if( p_spu != NULL ) |
498 | 106 | decoder_QueueSub( p_dec, p_spu ); |
499 | 106 | } |
500 | | |
501 | 668 | end: |
502 | 668 | block_Release(p_block); |
503 | 668 | return VLCDEC_SUCCESS; |
504 | 172 | } |
505 | | |
506 | | /* following functions are local */ |
507 | | |
508 | | /***************************************************************************** |
509 | | * default_clut_init: default clut as defined in EN 300-743 section 10 |
510 | | *****************************************************************************/ |
511 | | static void default_clut_init( decoder_t *p_dec ) |
512 | 1.31k | { |
513 | 1.31k | decoder_sys_t *p_sys = p_dec->p_sys; |
514 | 1.31k | uint8_t i; |
515 | | |
516 | 26.3k | #define RGB_TO_Y(r, g, b) ((int16_t) 77 * r + 150 * g + 29 * b) / 256; |
517 | 26.3k | #define RGB_TO_U(r, g, b) ((int16_t) -44 * r - 87 * g + 131 * b) / 256; |
518 | 26.3k | #define RGB_TO_V(r, g, b) ((int16_t) 131 * r - 110 * g - 21 * b) / 256; |
519 | | |
520 | | /* 4 entries CLUT */ |
521 | 6.59k | for( i = 0; i < 4; i++ ) |
522 | 5.27k | { |
523 | 5.27k | uint8_t R = 0, G = 0, B = 0, T = 0; |
524 | | |
525 | 5.27k | if( !(i & 0x2) && !(i & 0x1) ) T = 0xFF; |
526 | 3.95k | else if( !(i & 0x2) && (i & 0x1) ) R = G = B = 0xFF; |
527 | 2.63k | else if( (i & 0x2) && !(i & 0x1) ) R = G = B = 0; |
528 | 1.31k | else R = G = B = 0x7F; |
529 | | |
530 | 5.27k | p_sys->default_clut.c_2b[i].Y = RGB_TO_Y(R,G,B); |
531 | 5.27k | p_sys->default_clut.c_2b[i].Cb = RGB_TO_V(R,G,B); |
532 | 5.27k | p_sys->default_clut.c_2b[i].Cr = RGB_TO_U(R,G,B); |
533 | 5.27k | p_sys->default_clut.c_2b[i].T = T; |
534 | 5.27k | } |
535 | | |
536 | | /* 16 entries CLUT */ |
537 | 22.4k | for( i = 0; i < 16; i++ ) |
538 | 21.1k | { |
539 | 21.1k | uint8_t R = 0, G = 0, B = 0, T = 0; |
540 | | |
541 | 21.1k | if( !(i & 0x8) ) |
542 | 10.5k | { |
543 | 10.5k | if( !(i & 0x4) && !(i & 0x2) && !(i & 0x1) ) |
544 | 1.31k | { |
545 | 1.31k | T = 0xFF; |
546 | 1.31k | } |
547 | 9.23k | else |
548 | 9.23k | { |
549 | 9.23k | R = (i & 0x1) ? 0xFF : 0; |
550 | 9.23k | G = (i & 0x2) ? 0xFF : 0; |
551 | 9.23k | B = (i & 0x4) ? 0xFF : 0; |
552 | 9.23k | } |
553 | 10.5k | } |
554 | 10.5k | else |
555 | 10.5k | { |
556 | 10.5k | R = (i & 0x1) ? 0x7F : 0; |
557 | 10.5k | G = (i & 0x2) ? 0x7F : 0; |
558 | 10.5k | B = (i & 0x4) ? 0x7F : 0; |
559 | 10.5k | } |
560 | | |
561 | 21.1k | p_sys->default_clut.c_4b[i].Y = RGB_TO_Y(R,G,B); |
562 | 21.1k | p_sys->default_clut.c_4b[i].Cr = RGB_TO_V(R,G,B); |
563 | 21.1k | p_sys->default_clut.c_4b[i].Cb = RGB_TO_U(R,G,B); |
564 | 21.1k | p_sys->default_clut.c_4b[i].T = T; |
565 | 21.1k | } |
566 | | |
567 | | /* 256 entries CLUT */ |
568 | 1.31k | memset( p_sys->default_clut.c_8b, 0xFF, 256 * sizeof(dvbsub_color_t) ); |
569 | 1.31k | p_sys->default_clut.c_8b_entries = 256; |
570 | 1.31k | p_sys->default_clut.color_range = COLOR_RANGE_LIMITED; |
571 | 1.31k | p_sys->default_clut.dynamic_range_and_colour_gamut = DVBSUB_ST_COLORIMETRY_CDS; |
572 | 1.31k | } |
573 | | |
574 | | static void decode_segment( decoder_t *p_dec, bs_t *s ) |
575 | 2.78k | { |
576 | 2.78k | decoder_sys_t *p_sys = p_dec->p_sys; |
577 | 2.78k | int i_type; |
578 | 2.78k | int i_page_id; |
579 | 2.78k | int i_size; |
580 | | |
581 | | /* sync_byte (already checked) */ |
582 | | //bs_skip( s, 8 ); |
583 | | |
584 | | /* segment type */ |
585 | 2.78k | i_type = bs_read( s, 8 ); |
586 | | |
587 | | /* page id */ |
588 | 2.78k | i_page_id = bs_read( s, 16 ); |
589 | | |
590 | | /* segment size */ |
591 | 2.78k | i_size = bs_read( s, 16 ); |
592 | | |
593 | 2.78k | if( ( i_page_id != p_sys->i_id ) && |
594 | 53 | ( i_page_id != p_sys->i_ancillary_id ) ) |
595 | 53 | { |
596 | | #ifdef DEBUG_DVBSUB |
597 | | msg_Dbg( p_dec, "subtitle skipped (page id: %i, %i)", |
598 | | i_page_id, p_sys->i_id ); |
599 | | #endif |
600 | 53 | bs_skip( s, 8 * i_size ); |
601 | 53 | return; |
602 | 53 | } |
603 | | |
604 | 2.72k | if( ( p_sys->i_ancillary_id != p_sys->i_id ) && |
605 | 0 | ( i_type == DVBSUB_ST_PAGE_COMPOSITION ) && |
606 | 0 | ( i_page_id == p_sys->i_ancillary_id ) ) |
607 | 0 | { |
608 | | #ifdef DEBUG_DVBSUB |
609 | | msg_Dbg( p_dec, "skipped invalid ancillary subtitle packet" ); |
610 | | #endif |
611 | 0 | bs_skip( s, 8 * i_size ); |
612 | 0 | return; |
613 | 0 | } |
614 | | |
615 | | #ifdef DEBUG_DVBSUB |
616 | | if( i_page_id == p_sys->i_id ) |
617 | | msg_Dbg( p_dec, "segment (id: %i)", i_page_id ); |
618 | | else |
619 | | msg_Dbg( p_dec, "ancillary segment (id: %i)", i_page_id ); |
620 | | #endif |
621 | | |
622 | 2.72k | switch( i_type ) |
623 | 2.72k | { |
624 | 478 | case DVBSUB_ST_PAGE_COMPOSITION: |
625 | | #ifdef DEBUG_DVBSUB |
626 | | msg_Dbg( p_dec, "decode_page_composition" ); |
627 | | #endif |
628 | 478 | decode_page_composition( p_dec, s, i_size ); |
629 | 478 | break; |
630 | | |
631 | 424 | case DVBSUB_ST_REGION_COMPOSITION: |
632 | | #ifdef DEBUG_DVBSUB |
633 | | msg_Dbg( p_dec, "decode_region_composition" ); |
634 | | #endif |
635 | 424 | decode_region_composition( p_dec, s, i_size ); |
636 | 424 | break; |
637 | | |
638 | 337 | case DVBSUB_ST_CLUT_DEFINITION: |
639 | | #ifdef DEBUG_DVBSUB |
640 | | msg_Dbg( p_dec, "decode_clut" ); |
641 | | #endif |
642 | 337 | decode_clut( p_dec, s, i_size ); |
643 | 337 | break; |
644 | | |
645 | 488 | case DVBSUB_ST_OBJECT_DATA: |
646 | | #ifdef DEBUG_DVBSUB |
647 | | msg_Dbg( p_dec, "decode_object" ); |
648 | | #endif |
649 | 488 | decode_object( p_dec, s, i_size ); |
650 | 488 | break; |
651 | | |
652 | 476 | case DVBSUB_ST_DISPLAY_DEFINITION: |
653 | | #ifdef DEBUG_DVBSUB |
654 | | msg_Dbg( p_dec, "decode_display_definition" ); |
655 | | #endif |
656 | 476 | decode_display_definition( p_dec, s, i_size ); |
657 | 476 | break; |
658 | | |
659 | 212 | case DVBSUB_ST_ALTERNATE_CLUT: |
660 | | #ifdef DEBUG_DVBSUB |
661 | | msg_Dbg( p_dec, "alternative_CLUT" ); |
662 | | #endif |
663 | 212 | alternative_CLUT( p_dec, s, i_size ); |
664 | 212 | break; |
665 | | |
666 | 109 | case DVBSUB_ST_ENDOFDISPLAY: |
667 | | #ifdef DEBUG_DVBSUB |
668 | | msg_Dbg( p_dec, "end of display" ); |
669 | | #endif |
670 | 109 | bs_skip( s, 8 * i_size ); |
671 | 109 | break; |
672 | | |
673 | 116 | case DVBSUB_ST_STUFFING: |
674 | | #ifdef DEBUG_DVBSUB |
675 | | msg_Dbg( p_dec, "skip stuffing" ); |
676 | | #endif |
677 | 116 | bs_skip( s, 8 * i_size ); |
678 | 116 | break; |
679 | | |
680 | 87 | default: |
681 | 87 | msg_Warn( p_dec, "unsupported segment type: (%04x)", i_type ); |
682 | 87 | bs_skip( s, 8 * i_size ); |
683 | 87 | break; |
684 | 2.72k | } |
685 | 2.72k | } |
686 | | |
687 | | static void decode_clut( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
688 | 337 | { |
689 | 337 | decoder_sys_t *p_sys = p_dec->p_sys; |
690 | 337 | uint16_t i_processed_length; |
691 | 337 | dvbsub_clut_t *p_clut, *p_next; |
692 | 337 | int i_id, i_version; |
693 | | |
694 | 337 | i_id = bs_read( s, 8 ); |
695 | 337 | i_version = bs_read( s, 4 ); |
696 | | |
697 | | /* Check if we already have this clut */ |
698 | 528 | for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next ) |
699 | 331 | { |
700 | 331 | if( p_clut->i_id == i_id ) break; |
701 | 331 | } |
702 | | |
703 | | /* Check version number */ |
704 | 337 | if( p_clut && ( p_clut->i_version == i_version ) ) |
705 | 131 | { |
706 | | /* Nothing to do */ |
707 | 131 | bs_skip( s, 8 * i_segment_length - 12 ); |
708 | 131 | return; |
709 | 131 | } |
710 | | |
711 | 206 | if( !p_clut ) |
712 | 197 | { |
713 | | #ifdef DEBUG_DVBSUB |
714 | | msg_Dbg( p_dec, "new clut: %i", i_id ); |
715 | | #endif |
716 | 197 | p_clut = malloc( sizeof( dvbsub_clut_t ) ); |
717 | 197 | if( !p_clut ) |
718 | 0 | return; |
719 | 197 | p_clut->p_next = p_sys->p_cluts; |
720 | 197 | p_sys->p_cluts = p_clut; |
721 | 197 | } |
722 | | |
723 | | /* Initialize to default clut */ |
724 | 206 | p_next = p_clut->p_next; |
725 | 206 | *p_clut = p_sys->default_clut; |
726 | 206 | p_clut->p_next = p_next; |
727 | | |
728 | | /* We don't have this version of the CLUT: Parse it */ |
729 | 206 | p_clut->i_version = i_version; |
730 | 206 | p_clut->i_id = i_id; |
731 | 206 | bs_skip( s, 4 ); /* Reserved bits */ |
732 | 206 | i_processed_length = 2; |
733 | 140k | while( i_processed_length < i_segment_length ) |
734 | 140k | { |
735 | 140k | uint8_t y, cb, cr, t; |
736 | 140k | uint_fast8_t cid = bs_read( s, 8 ); |
737 | 140k | uint_fast8_t type = bs_read( s, 3 ); |
738 | | |
739 | 140k | bs_skip( s, 4 ); |
740 | | |
741 | 140k | p_clut->color_range = bs_read( s, 1 ) ? COLOR_RANGE_FULL : COLOR_RANGE_LIMITED; |
742 | 140k | if( p_clut->color_range == COLOR_RANGE_FULL ) |
743 | 619 | { |
744 | 619 | y = bs_read( s, 8 ); |
745 | 619 | cr = bs_read( s, 8 ); |
746 | 619 | cb = bs_read( s, 8 ); |
747 | 619 | t = bs_read( s, 8 ); |
748 | 619 | i_processed_length += 6; |
749 | 619 | } |
750 | 139k | else |
751 | 139k | { |
752 | 139k | y = bs_read( s, 6 ) << 2; |
753 | 139k | cr = bs_read( s, 4 ) << 4; |
754 | 139k | cb = bs_read( s, 4 ) << 4; |
755 | 139k | t = bs_read( s, 2 ) << 6; |
756 | 139k | i_processed_length += 4; |
757 | 139k | } |
758 | | |
759 | | /* We are not entirely compliant here as full transparency is indicated |
760 | | * with a luma value of zero, not a transparency value of 0xff |
761 | | * (full transparency would actually be 0xff + 1). */ |
762 | 140k | if( y == 0 ) |
763 | 139k | { |
764 | 139k | cr = cb = 0; |
765 | 139k | t = 0xff; |
766 | 139k | } |
767 | | |
768 | | /* According to EN 300-743 section 7.2.3 note 1, type should |
769 | | * not have more than 1 bit set to one, but some streams don't |
770 | | * respect this note. */ |
771 | 140k | if( ( type & 0x04 ) && ( cid < 4 ) ) |
772 | 171 | { |
773 | 171 | p_clut->c_2b[cid].Y = y; |
774 | 171 | p_clut->c_2b[cid].Cr = cr; |
775 | 171 | p_clut->c_2b[cid].Cb = cb; |
776 | 171 | p_clut->c_2b[cid].T = t; |
777 | 171 | } |
778 | 140k | if( ( type & 0x02 ) && ( cid < 16 ) ) |
779 | 181 | { |
780 | 181 | p_clut->c_4b[cid].Y = y; |
781 | 181 | p_clut->c_4b[cid].Cr = cr; |
782 | 181 | p_clut->c_4b[cid].Cb = cb; |
783 | 181 | p_clut->c_4b[cid].T = t; |
784 | 181 | } |
785 | 140k | if( type & 0x01 ) |
786 | 569 | { |
787 | 569 | p_clut->c_8b[cid].Y = y; |
788 | 569 | p_clut->c_8b[cid].Cr = cr; |
789 | 569 | p_clut->c_8b[cid].Cb = cb; |
790 | 569 | p_clut->c_8b[cid].T = t; |
791 | 569 | } |
792 | 140k | } |
793 | 206 | } |
794 | | |
795 | | static void decode_page_composition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
796 | 478 | { |
797 | 478 | decoder_sys_t *p_sys = p_dec->p_sys; |
798 | 478 | int i_version, i_state, i_timeout, i; |
799 | | |
800 | | /* A page is composed by 0 or more region */ |
801 | 478 | i_timeout = bs_read( s, 8 ); |
802 | 478 | i_version = bs_read( s, 4 ); |
803 | 478 | i_state = bs_read( s, 2 ); |
804 | 478 | bs_skip( s, 2 ); /* Reserved */ |
805 | | |
806 | 478 | if( i_state == DVBSUB_PCS_STATE_CHANGE ) |
807 | 4 | { |
808 | | /* End of an epoch, reset decoder buffer */ |
809 | | #ifdef DEBUG_DVBSUB |
810 | | msg_Dbg( p_dec, "page composition mode change" ); |
811 | | #endif |
812 | 4 | free_all( p_dec ); |
813 | 4 | } |
814 | 474 | else if( !p_sys->p_page && ( i_state != DVBSUB_PCS_STATE_ACQUISITION ) && |
815 | 66 | ( i_state != DVBSUB_PCS_STATE_CHANGE ) ) |
816 | 66 | { |
817 | | /* Not a full PCS, we need to wait for one */ |
818 | 66 | msg_Dbg( p_dec, "didn't receive an acquisition page yet" ); |
819 | | |
820 | | #if 0 |
821 | | /* Try to start decoding even without an acquisition page */ |
822 | | bs_skip( s, 8 * (i_segment_length - 2) ); |
823 | | return; |
824 | | #endif |
825 | 66 | } |
826 | | |
827 | | #ifdef DEBUG_DVBSUB |
828 | | if( i_state == DVBSUB_PCS_STATE_ACQUISITION ) |
829 | | msg_Dbg( p_dec, "acquisition page composition" ); |
830 | | #endif |
831 | | |
832 | | /* Check version number */ |
833 | 478 | if( p_sys->p_page && ( p_sys->p_page->i_version == i_version ) ) |
834 | 170 | { |
835 | 170 | bs_skip( s, 8 * (i_segment_length - 2) ); |
836 | 170 | return; |
837 | 170 | } |
838 | 308 | else if( p_sys->p_page ) |
839 | 98 | { |
840 | 98 | if( p_sys->p_page->i_region_defs ) |
841 | 97 | free( p_sys->p_page->p_region_defs ); |
842 | 98 | p_sys->p_page->p_region_defs = NULL; |
843 | 98 | p_sys->p_page->i_region_defs = 0; |
844 | 98 | } |
845 | | |
846 | 308 | if( !p_sys->p_page ) |
847 | 210 | { |
848 | | #ifdef DEBUG_DVBSUB |
849 | | msg_Dbg( p_dec, "new page" ); |
850 | | #endif |
851 | | /* Allocate a new page */ |
852 | 210 | p_sys->p_page = malloc( sizeof(dvbsub_page_t) ); |
853 | 210 | if( !p_sys->p_page ) |
854 | 0 | return; |
855 | 210 | } |
856 | | |
857 | 308 | p_sys->p_page->i_version = i_version; |
858 | 308 | p_sys->p_page->i_timeout = i_timeout; |
859 | 308 | p_sys->b_page = true; |
860 | | |
861 | | /* Number of regions */ |
862 | 308 | uint16_t i_region_defs = (i_segment_length - 2) / 6; |
863 | | |
864 | 308 | if( i_region_defs == 0 ) return; |
865 | | |
866 | 306 | p_sys->p_page->p_region_defs = |
867 | 306 | vlc_alloc( i_region_defs, sizeof(dvbsub_regiondef_t) ); |
868 | 306 | if( p_sys->p_page->p_region_defs ) |
869 | 306 | { |
870 | 306 | p_sys->p_page->i_region_defs = i_region_defs; |
871 | 42.3k | for( i = 0; i < p_sys->p_page->i_region_defs; i++ ) |
872 | 42.0k | { |
873 | 42.0k | p_sys->p_page->p_region_defs[i].i_id = bs_read( s, 8 ); |
874 | 42.0k | bs_skip( s, 8 ); /* Reserved */ |
875 | 42.0k | p_sys->p_page->p_region_defs[i].i_x = bs_read( s, 16 ); |
876 | 42.0k | p_sys->p_page->p_region_defs[i].i_y = bs_read( s, 16 ); |
877 | | |
878 | | #ifdef DEBUG_DVBSUB |
879 | | msg_Dbg( p_dec, "page_composition, region %i (%i,%i)", |
880 | | i, p_sys->p_page->p_region_defs[i].i_x, |
881 | | p_sys->p_page->p_region_defs[i].i_y ); |
882 | | #endif |
883 | 42.0k | } |
884 | 306 | } |
885 | 306 | } |
886 | | |
887 | | static void decode_region_composition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
888 | 424 | { |
889 | 424 | decoder_sys_t *p_sys = p_dec->p_sys; |
890 | 424 | dvbsub_region_t *p_region, **pp_region = &p_sys->p_regions; |
891 | 424 | int i_processed_length, i_id, i_version; |
892 | 424 | int i_width, i_height, i_level_comp, i_depth, i_clut; |
893 | 424 | int i_8_bg, i_4_bg, i_2_bg; |
894 | 424 | bool b_fill; |
895 | | |
896 | 424 | i_id = bs_read( s, 8 ); |
897 | 424 | i_version = bs_read( s, 4 ); |
898 | | |
899 | | /* Check if we already have this region */ |
900 | 557 | for( p_region = p_sys->p_regions; p_region != NULL; |
901 | 424 | p_region = p_region->p_next ) |
902 | 257 | { |
903 | 257 | pp_region = &p_region->p_next; |
904 | 257 | if( p_region->i_id == i_id ) break; |
905 | 257 | } |
906 | | |
907 | | /* Check version number */ |
908 | 424 | if( p_region && ( p_region->i_version == i_version ) ) |
909 | 123 | { |
910 | 123 | bs_skip( s, 8 * (i_segment_length - 1) - 4 ); |
911 | 123 | return; |
912 | 123 | } |
913 | | |
914 | 301 | if( !p_region ) |
915 | 300 | { |
916 | | #ifdef DEBUG_DVBSUB |
917 | | msg_Dbg( p_dec, "new region: %i", i_id ); |
918 | | #endif |
919 | 300 | p_region = *pp_region = calloc( 1, sizeof(dvbsub_region_t) ); |
920 | 300 | if( !p_region ) |
921 | 0 | return; |
922 | 300 | p_region->p_object_defs = NULL; |
923 | 300 | p_region->p_pixbuf = NULL; |
924 | 300 | p_region->p_next = NULL; |
925 | 300 | } |
926 | | |
927 | | /* Region attributes */ |
928 | 301 | p_region->i_id = i_id; |
929 | 301 | p_region->i_version = i_version; |
930 | 301 | b_fill = bs_read( s, 1 ); |
931 | 301 | bs_skip( s, 3 ); /* Reserved */ |
932 | | |
933 | 301 | i_width = bs_read( s, 16 ); |
934 | 301 | i_height = bs_read( s, 16 ); |
935 | | #ifdef DEBUG_DVBSUB |
936 | | msg_Dbg( p_dec, " width=%d height=%d", i_width, i_height ); |
937 | | #endif |
938 | 301 | i_level_comp = bs_read( s, 3 ); |
939 | 301 | i_depth = bs_read( s, 3 ); |
940 | 301 | bs_skip( s, 2 ); /* Reserved */ |
941 | 301 | i_clut = bs_read( s, 8 ); |
942 | | |
943 | 301 | i_8_bg = bs_read( s, 8 ); |
944 | 301 | i_4_bg = bs_read( s, 4 ); |
945 | 301 | i_2_bg = bs_read( s, 2 ); |
946 | 301 | bs_skip( s, 2 ); /* Reserved */ |
947 | | |
948 | | /* Free old object defs */ |
949 | 302 | while( p_region->i_object_defs ) |
950 | 1 | free( p_region->p_object_defs[--p_region->i_object_defs].psz_text ); |
951 | | |
952 | 301 | free( p_region->p_object_defs ); |
953 | 301 | p_region->p_object_defs = NULL; |
954 | | |
955 | | /* Extra sanity checks */ |
956 | 301 | if( ( p_region->i_width != i_width ) || |
957 | 8 | ( p_region->i_height != i_height ) ) |
958 | 300 | { |
959 | 300 | if( p_region->p_pixbuf ) |
960 | 1 | { |
961 | 1 | msg_Dbg( p_dec, "region size changed (%dx%d->%dx%d)", |
962 | 1 | p_region->i_width, p_region->i_height, i_width, i_height ); |
963 | 1 | } |
964 | | |
965 | 300 | size_t i_alloc; |
966 | 300 | if( ckd_mul( &i_alloc, i_width, i_height ) ) |
967 | 0 | { |
968 | 0 | free( p_region->p_pixbuf ); |
969 | 0 | p_region->p_pixbuf = NULL; |
970 | 0 | } |
971 | 300 | else |
972 | 300 | { |
973 | 300 | p_region->p_pixbuf = realloc_or_free( p_region->p_pixbuf, i_alloc ); |
974 | 300 | p_region->i_depth = 0; |
975 | 300 | } |
976 | | |
977 | 300 | b_fill = !!p_region->p_pixbuf; |
978 | 300 | } |
979 | | |
980 | 301 | if( p_region->i_depth && |
981 | 0 | ( ( p_region->i_depth != i_depth ) || |
982 | 0 | ( p_region->i_level_comp != i_level_comp ) || |
983 | 0 | ( p_region->i_clut != i_clut) ) ) |
984 | 0 | { |
985 | 0 | msg_Dbg( p_dec, "region parameters changed (not allowed)" ); |
986 | 0 | } |
987 | | |
988 | | /* Erase background of region */ |
989 | 301 | if( b_fill ) |
990 | 300 | { |
991 | 300 | int i_background = ( i_depth == 1 ) ? i_2_bg : |
992 | 300 | ( ( i_depth == 2 ) ? i_4_bg : i_8_bg ); |
993 | 300 | memset( p_region->p_pixbuf, i_background, (size_t)i_width * i_height ); |
994 | 300 | } |
995 | | |
996 | 301 | p_region->i_width = i_width; |
997 | 301 | p_region->i_height = i_height; |
998 | 301 | p_region->i_level_comp = i_level_comp; |
999 | 301 | p_region->i_depth = i_depth; |
1000 | 301 | p_region->i_clut = i_clut; |
1001 | | |
1002 | | /* List of objects in the region */ |
1003 | 301 | i_processed_length = 10; |
1004 | | |
1005 | | /* Entry can be 6 or 8 bytes */ |
1006 | 301 | unsigned max_object_defs; |
1007 | 301 | if( i_segment_length < 10 ) |
1008 | 5 | max_object_defs = 0; |
1009 | 296 | else |
1010 | 296 | max_object_defs = (i_segment_length - i_processed_length) / 6; |
1011 | 301 | p_region->i_object_defs = 0; |
1012 | 301 | p_region->p_object_defs = realloc_or_free( p_region->p_object_defs, |
1013 | 301 | max_object_defs * sizeof(dvbsub_objectdef_t) ); |
1014 | 301 | if( !p_region->p_object_defs ) |
1015 | 0 | return; |
1016 | | |
1017 | 237k | while( i_processed_length < i_segment_length ) |
1018 | 236k | { |
1019 | 236k | dvbsub_objectdef_t *p_obj; |
1020 | | |
1021 | | /* We parse object properties */ |
1022 | 236k | p_obj = &p_region->p_object_defs[p_region->i_object_defs++]; |
1023 | 236k | p_obj->i_id = bs_read( s, 16 ); |
1024 | 236k | p_obj->i_type = bs_read( s, 2 ); |
1025 | 236k | bs_skip( s, 2 ); /* Provider */ |
1026 | 236k | p_obj->i_x = bs_read( s, 12 ); |
1027 | 236k | bs_skip( s, 4 ); /* Reserved */ |
1028 | 236k | p_obj->i_y = bs_read( s, 12 ); |
1029 | 236k | p_obj->psz_text = NULL; |
1030 | | |
1031 | 236k | i_processed_length += 6; |
1032 | | |
1033 | 236k | if( ( p_obj->i_type == DVBSUB_OT_BASIC_CHAR ) || |
1034 | 236k | ( p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING ) ) |
1035 | 71 | { |
1036 | 71 | p_obj->i_fg_pc = bs_read( s, 8 ); |
1037 | 71 | p_obj->i_bg_pc = bs_read( s, 8 ); |
1038 | 71 | i_processed_length += 2; |
1039 | 71 | } |
1040 | 236k | } |
1041 | 301 | } |
1042 | | |
1043 | | /* ETSI 300 743 [7.2.8] */ |
1044 | | static void alternative_CLUT( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
1045 | 212 | { |
1046 | 212 | decoder_sys_t *p_sys = p_dec->p_sys; |
1047 | 212 | uint16_t i_processed_length; |
1048 | 212 | int i_id, i_version; |
1049 | 212 | dvbsub_clut_t *p_clut; |
1050 | | |
1051 | 212 | i_id = bs_read( s, 8 ); |
1052 | 212 | i_version = bs_read( s, 4 ); |
1053 | | |
1054 | | /* Check if we already have this clut */ |
1055 | 397 | for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next ) |
1056 | 257 | { |
1057 | 257 | if( p_clut->i_id == i_id ) |
1058 | 72 | { |
1059 | | /* Check version number */ |
1060 | 72 | if( p_clut->i_version == i_version ) |
1061 | 70 | { |
1062 | | /* Nothing to do */ |
1063 | 70 | bs_skip( s, 8 * i_segment_length - 12 ); |
1064 | 70 | return; |
1065 | 70 | } |
1066 | | |
1067 | 2 | break; |
1068 | 72 | } |
1069 | 257 | } |
1070 | | |
1071 | 142 | if( !p_clut ) |
1072 | 140 | { |
1073 | | #ifdef DEBUG_DVBSUB |
1074 | | msg_Dbg( p_dec, "new alternative clut: %i", i_id ); |
1075 | | #endif |
1076 | 140 | p_clut = malloc( sizeof( dvbsub_clut_t ) ); |
1077 | 140 | if( !p_clut ) |
1078 | 0 | return; |
1079 | 140 | p_clut->p_next = p_sys->p_cluts; |
1080 | 140 | p_sys->p_cluts = p_clut; |
1081 | 140 | } |
1082 | | |
1083 | | /* We don't have this version of the CLUT: Parse it */ |
1084 | 142 | p_clut->i_version = i_version; |
1085 | 142 | p_clut->i_id = i_id; |
1086 | | |
1087 | 142 | bs_skip( s, 4 ); // reserved_zero_future_use |
1088 | | |
1089 | | // CLUT_parameters |
1090 | 142 | int CLUT_entry_max_number = bs_read( s, 2 ); |
1091 | 142 | int colour_component_type = bs_read( s, 2 ); |
1092 | 142 | int output_bit_depth = bs_read( s, 3 ); |
1093 | 142 | bs_skip( s, 1 ); // reserved_zero_future_use |
1094 | 142 | int dynamic_range_and_colour_gamut = bs_read( s, 8 ); |
1095 | | |
1096 | 142 | bool error = false; |
1097 | 142 | i_processed_length = 4; |
1098 | 142 | if (output_bit_depth != DVBSUB_ST_BITDEPTH_8BIT && |
1099 | 28 | output_bit_depth != DVBSUB_ST_BITDEPTH_10BIT) |
1100 | 27 | { |
1101 | 27 | msg_Err( p_dec, "unsupported alternative clut bitdepth: %i", output_bit_depth ); |
1102 | 27 | error = true; |
1103 | 27 | } |
1104 | 142 | if (CLUT_entry_max_number != 0) // 0: 256 entries |
1105 | 24 | { |
1106 | 24 | msg_Err( p_dec, "unsupported alternative clut max entries: %i", CLUT_entry_max_number ); |
1107 | 24 | error = true; |
1108 | 24 | } |
1109 | 142 | if (colour_component_type != 0) // 0: YCbCr |
1110 | 17 | { |
1111 | 17 | msg_Err( p_dec, "unsupported alternative clut component type: %i", colour_component_type ); |
1112 | 17 | error = true; |
1113 | 17 | } |
1114 | 142 | if (dynamic_range_and_colour_gamut > DVBSUB_ST_COLORIMETRY_HDR_HLG) |
1115 | 20 | { |
1116 | 20 | msg_Err( p_dec, "unsupported alternative clut color range: %i", dynamic_range_and_colour_gamut ); |
1117 | 20 | error = true; |
1118 | 20 | } |
1119 | 142 | if (error) |
1120 | 36 | goto done; |
1121 | | |
1122 | 106 | p_clut->c_8b_entries = 0; |
1123 | 4.71k | while( i_processed_length < i_segment_length ) |
1124 | 4.62k | { |
1125 | 4.62k | uint8_t y, cb, cr, t; |
1126 | 4.62k | if (output_bit_depth == DVBSUB_ST_BITDEPTH_10BIT) |
1127 | 0 | { |
1128 | | // TODO: apply the palette locally to keep 10-bit values |
1129 | 0 | y = bs_read( s, 10 ) >> 2; |
1130 | 0 | cr = bs_read( s, 10 ) >> 2; |
1131 | 0 | cb = bs_read( s, 10 ) >> 2; |
1132 | 0 | t = bs_read( s, 10 ) >> 2; |
1133 | 0 | i_processed_length += 5; |
1134 | 0 | } |
1135 | 4.62k | else |
1136 | 4.62k | { |
1137 | 4.62k | y = bs_read( s, 8 ); |
1138 | 4.62k | cr = bs_read( s, 8 ); |
1139 | 4.62k | cb = bs_read( s, 8 ); |
1140 | 4.62k | t = bs_read( s, 8 ); |
1141 | 4.62k | i_processed_length += 4; |
1142 | 4.62k | } |
1143 | | |
1144 | | /* We are not entirely compliant here as full transparency is indicated |
1145 | | * with a luma value of zero, not a transparency value of 0xff |
1146 | | * (full transparency would actually be 0xff + 1). */ |
1147 | 4.62k | if( y == 0 ) |
1148 | 4.27k | { |
1149 | 4.27k | cr = cb = 0; |
1150 | 4.27k | t = 0xff; |
1151 | 4.27k | } |
1152 | | |
1153 | 4.62k | p_clut->c_8b[p_clut->c_8b_entries].Y = y; |
1154 | 4.62k | p_clut->c_8b[p_clut->c_8b_entries].Cr = cr; |
1155 | 4.62k | p_clut->c_8b[p_clut->c_8b_entries].Cb = cb; |
1156 | 4.62k | p_clut->c_8b[p_clut->c_8b_entries].T = t; |
1157 | 4.62k | p_clut->c_8b_entries++; |
1158 | 4.62k | if (p_clut->c_8b_entries >= (int)ARRAY_SIZE(p_clut->c_8b)) |
1159 | 17 | break; |
1160 | 4.62k | } |
1161 | 106 | p_clut->dynamic_range_and_colour_gamut = dynamic_range_and_colour_gamut; |
1162 | 106 | p_clut->color_range = COLOR_RANGE_FULL; |
1163 | 142 | done: |
1164 | 142 | bs_skip( s, 8 * (i_segment_length - i_processed_length) ); |
1165 | 142 | } |
1166 | | |
1167 | | /* ETSI 300 743 [7.2.1] */ |
1168 | | static void decode_display_definition( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
1169 | 476 | { |
1170 | 476 | decoder_sys_t *p_sys = p_dec->p_sys; |
1171 | 476 | uint16_t i_processed_length = 40; |
1172 | 476 | int i_version; |
1173 | | |
1174 | 476 | i_version = bs_read( s, 4 ); |
1175 | | |
1176 | | /* Check version number */ |
1177 | 476 | if( p_sys->display.i_version == i_version ) |
1178 | 24 | { |
1179 | | /* The definition did not change */ |
1180 | 24 | bs_skip( s, 8*i_segment_length - 4 ); |
1181 | 24 | return; |
1182 | 24 | } |
1183 | | |
1184 | | #ifdef DEBUG_DVBSUB |
1185 | | msg_Dbg( p_dec, "new display definition: %i", i_version ); |
1186 | | #endif |
1187 | | |
1188 | | /* We don't have this version of the display definition: Parse it */ |
1189 | 452 | p_sys->display.i_version = i_version; |
1190 | 452 | p_sys->display.b_windowed = bs_read( s, 1 ); |
1191 | 452 | bs_skip( s, 3 ); /* Reserved bits */ |
1192 | 452 | p_sys->display.i_width_minus1 = bs_read( s, 16 ); |
1193 | 452 | p_sys->display.i_height_minus1 = bs_read( s, 16 ); |
1194 | | |
1195 | 452 | if( p_sys->display.b_windowed ) |
1196 | 16 | { |
1197 | | #ifdef DEBUG_DVBSUB |
1198 | | msg_Dbg( p_dec, "display definition with offsets (windowed)" ); |
1199 | | #endif |
1200 | | /* Coordinates are measured from the top left corner */ |
1201 | 16 | p_sys->display.i_x = bs_read( s, 16 ); |
1202 | 16 | p_sys->display.i_max_x = bs_read( s, 16 ); |
1203 | 16 | p_sys->display.i_y = bs_read( s, 16 ); |
1204 | 16 | p_sys->display.i_max_y = bs_read( s, 16 ); |
1205 | 16 | i_processed_length += 64; |
1206 | 16 | } |
1207 | 436 | else |
1208 | 436 | { |
1209 | | /* if not windowed, setup the window variables to good defaults */ |
1210 | | /* not necessary, but to avoid future confusion.. */ |
1211 | 436 | p_sys->display.i_x = 0; |
1212 | 436 | p_sys->display.i_max_x = p_sys->display.i_width_minus1; |
1213 | 436 | p_sys->display.i_y = 0; |
1214 | 436 | p_sys->display.i_max_y = p_sys->display.i_height_minus1; |
1215 | 436 | } |
1216 | | |
1217 | 452 | if( i_processed_length != i_segment_length*8 ) |
1218 | 22 | { |
1219 | 22 | msg_Err( p_dec, "processed length %d bytes != segment length %d bytes", |
1220 | 22 | i_processed_length / 8 , i_segment_length ); |
1221 | 22 | } |
1222 | | |
1223 | | #ifdef DEBUG_DVBSUB |
1224 | | msg_Dbg( p_dec, "version: %d, width: %d, height: %d", |
1225 | | p_sys->display.i_version, (int)p_sys->display.i_width_minus1+1, (int)p_sys->display.i_height_minus1+1 ); |
1226 | | if( p_sys->display.b_windowed ) |
1227 | | msg_Dbg( p_dec, "xmin: %d, xmax: %d, ymin: %d, ymax: %d", |
1228 | | p_sys->display.i_x, p_sys->display.i_max_x, p_sys->display.i_y, p_sys->display.i_max_y ); |
1229 | | #endif |
1230 | 452 | } |
1231 | | |
1232 | | static void dvbsub_render_pdata( decoder_t *, dvbsub_region_t *, int, int, |
1233 | | uint8_t *, int ); |
1234 | | static void dvbsub_pdata2bpp( bs_t *, uint8_t *, int, int * ); |
1235 | | static void dvbsub_pdata4bpp( bs_t *, uint8_t *, int, int * ); |
1236 | | static void dvbsub_pdata8bpp( bs_t *, uint8_t *, int, int * ); |
1237 | | |
1238 | | static void decode_object( decoder_t *p_dec, bs_t *s, uint16_t i_segment_length ) |
1239 | 488 | { |
1240 | 488 | decoder_sys_t *p_sys = p_dec->p_sys; |
1241 | 488 | dvbsub_region_t *p_region; |
1242 | 488 | int i_coding_method, i_id, i; |
1243 | | |
1244 | | /* ETSI 300-743 v1.5.1 section 7.2.5 'Object data segment' |
1245 | | * sync_byte, segment_type, page_id and i_segment_length have already been processed. |
1246 | | */ |
1247 | 488 | i_id = bs_read( s, 16 ); |
1248 | 488 | bs_skip( s, 4 ); /* version */ |
1249 | 488 | i_coding_method = bs_read( s, 2 ); |
1250 | | |
1251 | 488 | if( i_coding_method > 1 ) |
1252 | 5 | { |
1253 | 5 | msg_Dbg( p_dec, "unknown DVB subtitling coding %d is not handled!", i_coding_method ); |
1254 | 5 | bs_skip( s, 8 * (i_segment_length - 2) - 6 ); |
1255 | 5 | return; |
1256 | 5 | } |
1257 | | |
1258 | | /* Check if the object needs to be rendered in at least one |
1259 | | * of the regions */ |
1260 | 766 | for( p_region = p_sys->p_regions; p_region != NULL; |
1261 | 483 | p_region = p_region->p_next ) |
1262 | 530 | { |
1263 | 74.9k | for( i = 0; i < p_region->i_object_defs; i++ ) |
1264 | 74.6k | if( p_region->p_object_defs[i].i_id == i_id ) break; |
1265 | | |
1266 | 530 | if( i != p_region->i_object_defs ) break; |
1267 | 530 | } |
1268 | 483 | if( !p_region ) |
1269 | 236 | { |
1270 | 236 | bs_skip( s, 8 * (i_segment_length - 2) - 6 ); |
1271 | 236 | return; |
1272 | 236 | } |
1273 | | |
1274 | | #ifdef DEBUG_DVBSUB |
1275 | | msg_Dbg( p_dec, "new object: %i", i_id ); |
1276 | | #endif |
1277 | | |
1278 | 247 | bs_skip( s, 1 ); /* non_modify_color */ |
1279 | 247 | bs_skip( s, 1 ); /* Reserved */ |
1280 | | |
1281 | 247 | if( i_coding_method == 0x00 ) |
1282 | 245 | { |
1283 | 245 | int i_topfield, i_bottomfield; |
1284 | 245 | uint8_t *p_topfield, *p_bottomfield; |
1285 | | |
1286 | 245 | i_topfield = bs_read( s, 16 ); |
1287 | 245 | i_bottomfield = bs_read( s, 16 ); |
1288 | 245 | p_topfield = s->p_start + bs_pos( s ) / 8; |
1289 | 245 | p_bottomfield = p_topfield + i_topfield; |
1290 | | |
1291 | 245 | bs_skip( s, 8 * (i_segment_length - 7) ); |
1292 | | |
1293 | | /* Sanity check */ |
1294 | 245 | if( ( i_segment_length < ( i_topfield + i_bottomfield + 7 ) ) || |
1295 | 175 | ( ( p_topfield + i_topfield + i_bottomfield ) > s->p_end ) ) |
1296 | 71 | { |
1297 | 71 | msg_Dbg( p_dec, "corrupted object data" ); |
1298 | 71 | return; |
1299 | 71 | } |
1300 | | |
1301 | 406 | for( p_region = p_sys->p_regions; p_region != NULL; |
1302 | 232 | p_region = p_region->p_next ) |
1303 | 232 | { |
1304 | 106k | for( i = 0; i < p_region->i_object_defs; i++ ) |
1305 | 106k | { |
1306 | 106k | if( p_region->p_object_defs[i].i_id != i_id ) continue; |
1307 | | |
1308 | 106k | dvbsub_render_pdata( p_dec, p_region, |
1309 | 106k | p_region->p_object_defs[i].i_x, |
1310 | 106k | p_region->p_object_defs[i].i_y, |
1311 | 106k | p_topfield, i_topfield ); |
1312 | | |
1313 | 106k | if( i_bottomfield ) |
1314 | 0 | { |
1315 | 0 | dvbsub_render_pdata( p_dec, p_region, |
1316 | 0 | p_region->p_object_defs[i].i_x, |
1317 | 0 | p_region->p_object_defs[i].i_y + 1, |
1318 | 0 | p_bottomfield, i_bottomfield ); |
1319 | 0 | } |
1320 | 106k | else |
1321 | 106k | { |
1322 | | /* Duplicate the top field */ |
1323 | 106k | dvbsub_render_pdata( p_dec, p_region, |
1324 | 106k | p_region->p_object_defs[i].i_x, |
1325 | 106k | p_region->p_object_defs[i].i_y + 1, |
1326 | 106k | p_topfield, i_topfield ); |
1327 | 106k | } |
1328 | 106k | } |
1329 | 232 | } |
1330 | 174 | } |
1331 | 2 | else |
1332 | 2 | { |
1333 | | /* DVB subtitling as characters */ |
1334 | 2 | int i_number_of_codes = bs_read( s, 8 ); |
1335 | 2 | uint8_t* p_start = s->p_start + bs_pos( s ) / 8; |
1336 | | |
1337 | | /* Sanity check */ |
1338 | 2 | if( ( i_segment_length < ( i_number_of_codes*2 + 4 ) ) || |
1339 | 1 | ( ( p_start + i_number_of_codes*2 ) > s->p_end ) ) |
1340 | 1 | { |
1341 | 1 | msg_Dbg( p_dec, "corrupted object data" ); |
1342 | 1 | return; |
1343 | 1 | } |
1344 | | |
1345 | 2 | for( p_region = p_sys->p_regions; p_region != NULL; |
1346 | 1 | p_region = p_region->p_next ) |
1347 | 1 | { |
1348 | 2 | for( i = 0; i < p_region->i_object_defs; i++ ) |
1349 | 1 | { |
1350 | 1 | int j; |
1351 | | |
1352 | 1 | if( p_region->p_object_defs[i].i_id != i_id ) continue; |
1353 | | |
1354 | 1 | char *psz_text = p_region->p_object_defs[i].psz_text; |
1355 | | |
1356 | 1 | p_region->p_object_defs[i].psz_text = psz_text = |
1357 | 1 | realloc_or_free( psz_text, i_number_of_codes + 1 ); |
1358 | | |
1359 | 1 | if( !psz_text ) |
1360 | 0 | continue; |
1361 | | |
1362 | | /* FIXME 16bits -> char ??? See Preamble */ |
1363 | 1 | for( j = 0; j < i_number_of_codes; j++ ) |
1364 | 0 | { |
1365 | 0 | psz_text[j] = (char)(bs_read( s, 16 ) & 0xFF); |
1366 | 0 | } |
1367 | | /* Null terminate the string */ |
1368 | 1 | psz_text[j] = 0; |
1369 | 1 | } |
1370 | 1 | } |
1371 | 1 | } |
1372 | | |
1373 | | #ifdef DEBUG_DVBSUB |
1374 | | msg_Dbg( p_dec, "end object: %i", i_id ); |
1375 | | #endif |
1376 | 247 | } |
1377 | | |
1378 | | static void dvbsub_render_pdata( decoder_t *p_dec, dvbsub_region_t *p_region, |
1379 | | int i_x, int i_y, |
1380 | | uint8_t *p_field, int i_field ) |
1381 | 212k | { |
1382 | 212k | uint8_t *p_pixbuf; |
1383 | 212k | int i_offset = 0; |
1384 | 212k | bs_t bs; |
1385 | | |
1386 | | /* Sanity check */ |
1387 | 212k | if( !p_region->p_pixbuf ) |
1388 | 0 | { |
1389 | 0 | msg_Err( p_dec, "region %i has no pixel buffer!", p_region->i_id ); |
1390 | 0 | return; |
1391 | 0 | } |
1392 | 212k | if( i_y < 0 || i_x < 0 || i_y >= p_region->i_height || |
1393 | 212k | i_x >= p_region->i_width ) |
1394 | 80.4k | { |
1395 | 80.4k | msg_Dbg( p_dec, "invalid offset (%i,%i)", i_x, i_y ); |
1396 | 80.4k | return; |
1397 | 80.4k | } |
1398 | | |
1399 | 132k | p_pixbuf = p_region->p_pixbuf + (size_t)i_y * p_region->i_width; |
1400 | 132k | bs_init( &bs, p_field, i_field ); |
1401 | | |
1402 | 2.25M | while( !bs_eof( &bs ) ) |
1403 | 2.12M | { |
1404 | | /* Sanity check */ |
1405 | 2.12M | if( i_y >= p_region->i_height ) return; |
1406 | | |
1407 | 2.12M | switch( bs_read( &bs, 8 ) ) |
1408 | 2.12M | { |
1409 | 143k | case 0x10: |
1410 | 143k | dvbsub_pdata2bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, |
1411 | 143k | &i_offset ); |
1412 | 143k | break; |
1413 | | |
1414 | 132k | case 0x11: |
1415 | 132k | dvbsub_pdata4bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, |
1416 | 132k | &i_offset ); |
1417 | 132k | break; |
1418 | | |
1419 | 120k | case 0x12: |
1420 | 120k | dvbsub_pdata8bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, |
1421 | 120k | &i_offset ); |
1422 | 120k | break; |
1423 | | |
1424 | 120k | case 0x20: |
1425 | 252k | case 0x21: |
1426 | 373k | case 0x22: |
1427 | | /* We don't use map tables */ |
1428 | 373k | break; |
1429 | | |
1430 | 120k | case 0xf0: /* End of line code */ |
1431 | 120k | p_pixbuf += 2*p_region->i_width; |
1432 | 120k | i_offset = 0; i_y += 2; |
1433 | 120k | break; |
1434 | 2.12M | } |
1435 | 2.12M | } |
1436 | 132k | } |
1437 | | |
1438 | | static void dvbsub_pdata2bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off ) |
1439 | 143k | { |
1440 | 143k | bool b_stop = false; |
1441 | | |
1442 | 310k | while( !b_stop && !bs_eof( s ) ) |
1443 | 166k | { |
1444 | 166k | int i_count = 0, i_color = 0; |
1445 | | |
1446 | 166k | i_color = bs_read( s, 2 ); |
1447 | 166k | if( i_color != 0x00 ) |
1448 | 87 | { |
1449 | 87 | i_count = 1; |
1450 | 87 | } |
1451 | 166k | else |
1452 | 166k | { |
1453 | 166k | if( bs_read( s, 1 ) == 0x01 ) // Switch1 |
1454 | 11.5k | { |
1455 | 11.5k | i_count = 3 + bs_read( s, 3 ); |
1456 | 11.5k | i_color = bs_read( s, 2 ); |
1457 | 11.5k | } |
1458 | 155k | else |
1459 | 155k | { |
1460 | 155k | if( bs_read( s, 1 ) == 0x00 ) //Switch2 |
1461 | 143k | { |
1462 | 143k | switch( bs_read( s, 2 ) ) //Switch3 |
1463 | 143k | { |
1464 | 143k | case 0x00: |
1465 | 143k | b_stop = true; |
1466 | 143k | break; |
1467 | 0 | case 0x01: |
1468 | 0 | i_count = 2; |
1469 | 0 | break; |
1470 | 0 | case 0x02: |
1471 | 0 | i_count = 12 + bs_read( s, 4 ); |
1472 | 0 | i_color = bs_read( s, 2 ); |
1473 | 0 | break; |
1474 | 2 | case 0x03: |
1475 | 2 | i_count = 29 + bs_read( s, 8 ); |
1476 | 2 | i_color = bs_read( s, 2 ); |
1477 | 2 | break; |
1478 | 0 | default: |
1479 | 0 | break; |
1480 | 143k | } |
1481 | 143k | } |
1482 | 11.4k | else |
1483 | 11.4k | { |
1484 | | /* 1 pixel color 0 */ |
1485 | 11.4k | i_count = 1; |
1486 | 11.4k | } |
1487 | 155k | } |
1488 | 166k | } |
1489 | | |
1490 | 166k | if( !i_count ) continue; |
1491 | | |
1492 | | /* Sanity check */ |
1493 | 23.0k | if( ( i_count + *pi_off ) > i_width ) break; |
1494 | | |
1495 | 23.0k | if( i_count == 1 ) p[*pi_off] = i_color; |
1496 | 11.4k | else memset( ( p + *pi_off ), i_color, i_count ); |
1497 | | |
1498 | 23.0k | (*pi_off) += i_count; |
1499 | 23.0k | } |
1500 | | |
1501 | 143k | bs_align( s ); |
1502 | 143k | } |
1503 | | |
1504 | | static void dvbsub_pdata4bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off ) |
1505 | 132k | { |
1506 | 132k | bool b_stop = false; |
1507 | | |
1508 | 471k | while( !b_stop && !bs_eof( s ) ) |
1509 | 338k | { |
1510 | 338k | int i_count = 0, i_color = 0; |
1511 | | |
1512 | 338k | i_color = bs_read( s, 4 ); |
1513 | 338k | if( i_color != 0x00 ) |
1514 | 206k | { |
1515 | | /* Add 1 pixel */ |
1516 | 206k | i_count = 1; |
1517 | 206k | } |
1518 | 132k | else |
1519 | 132k | { |
1520 | 132k | if( bs_read( s, 1 ) == 0x00 ) // Switch1 |
1521 | 132k | { |
1522 | 132k | i_count = bs_read( s, 3 ); |
1523 | 132k | if( i_count != 0x00 ) |
1524 | 4 | { |
1525 | 4 | i_count += 2; |
1526 | 4 | } |
1527 | 132k | else b_stop = true; |
1528 | 132k | } |
1529 | 14 | else |
1530 | 14 | { |
1531 | 14 | if( bs_read( s, 1 ) == 0x00) //Switch2 |
1532 | 12 | { |
1533 | 12 | i_count = 4 + bs_read( s, 2 ); |
1534 | 12 | i_color = bs_read( s, 4 ); |
1535 | 12 | } |
1536 | 2 | else |
1537 | 2 | { |
1538 | 2 | switch ( bs_read( s, 2 ) ) //Switch3 |
1539 | 2 | { |
1540 | 0 | case 0x0: |
1541 | 0 | i_count = 1; |
1542 | 0 | break; |
1543 | 0 | case 0x1: |
1544 | 0 | i_count = 2; |
1545 | 0 | break; |
1546 | 0 | case 0x2: |
1547 | 0 | i_count = 9 + bs_read( s, 4 ); |
1548 | 0 | i_color = bs_read( s, 4 ); |
1549 | 0 | break; |
1550 | 2 | case 0x3: |
1551 | 2 | i_count= 25 + bs_read( s, 8 ); |
1552 | 2 | i_color = bs_read( s, 4 ); |
1553 | 2 | break; |
1554 | 2 | } |
1555 | 2 | } |
1556 | 14 | } |
1557 | 132k | } |
1558 | | |
1559 | 338k | if( !i_count ) continue; |
1560 | | |
1561 | | /* Sanity check */ |
1562 | 206k | if( ( i_count + *pi_off ) > i_width ) break; |
1563 | | |
1564 | 206k | if( i_count == 1 ) p[*pi_off] = i_color; |
1565 | 16 | else memset( ( p + *pi_off ), i_color, i_count ); |
1566 | | |
1567 | 206k | (*pi_off) += i_count; |
1568 | 206k | } |
1569 | | |
1570 | 132k | bs_align( s ); |
1571 | 132k | } |
1572 | | |
1573 | | static void dvbsub_pdata8bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off ) |
1574 | 120k | { |
1575 | 120k | bool b_stop = false; |
1576 | | |
1577 | 229k | while( !b_stop && !bs_eof( s ) ) |
1578 | 132k | { |
1579 | 132k | int i_count = 0, i_color = 0; |
1580 | | |
1581 | 132k | i_color = bs_read( s, 8 ); |
1582 | 132k | if( i_color != 0x00 ) |
1583 | 11.5k | { |
1584 | | /* Add 1 pixel */ |
1585 | 11.5k | i_count = 1; |
1586 | 11.5k | } |
1587 | 120k | else |
1588 | 120k | { |
1589 | 120k | if( bs_read( s, 1 ) == 0x00 ) // Switch1 |
1590 | 120k | { |
1591 | 120k | i_count = bs_read( s, 7 ); |
1592 | 120k | if( i_count == 0x00 ) |
1593 | 97.6k | b_stop = true; |
1594 | 120k | } |
1595 | 14 | else |
1596 | 14 | { |
1597 | 14 | i_count = bs_read( s, 7 ); |
1598 | 14 | i_color = bs_read( s, 8 ); |
1599 | 14 | } |
1600 | 120k | } |
1601 | | |
1602 | 132k | if( !i_count ) continue; |
1603 | | |
1604 | | /* Sanity check */ |
1605 | 34.5k | if( ( i_count + *pi_off ) > i_width ) break; |
1606 | | |
1607 | 11.5k | if( i_count == 1 ) p[*pi_off] = i_color; |
1608 | 14 | else memset( ( p + *pi_off ), i_color, i_count ); |
1609 | | |
1610 | 11.5k | (*pi_off) += i_count; |
1611 | 11.5k | } |
1612 | | |
1613 | 120k | bs_align( s ); |
1614 | 120k | } |
1615 | | |
1616 | | static void free_all( decoder_t *p_dec ) |
1617 | 1.32k | { |
1618 | 1.32k | decoder_sys_t *p_sys = p_dec->p_sys; |
1619 | 1.32k | dvbsub_region_t *p_reg, *p_reg_next; |
1620 | 1.32k | dvbsub_clut_t *p_clut, *p_clut_next; |
1621 | | |
1622 | | /*free( p_sys->p_display ); No longer malloced */ |
1623 | | |
1624 | 1.66k | for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut_next ) |
1625 | 337 | { |
1626 | 337 | p_clut_next = p_clut->p_next; |
1627 | 337 | free( p_clut ); |
1628 | 337 | } |
1629 | 1.32k | p_sys->p_cluts = NULL; |
1630 | | |
1631 | 1.62k | for( p_reg = p_sys->p_regions; p_reg != NULL; p_reg = p_reg_next ) |
1632 | 300 | { |
1633 | 300 | p_reg_next = p_reg->p_next; |
1634 | 237k | for( int i = 0; i < p_reg->i_object_defs; i++ ) |
1635 | 236k | free( p_reg->p_object_defs[i].psz_text ); |
1636 | 300 | free( p_reg->p_object_defs ); |
1637 | 300 | free( p_reg->p_pixbuf ); |
1638 | 300 | free( p_reg ); |
1639 | 300 | } |
1640 | 1.32k | p_sys->p_regions = NULL; |
1641 | | |
1642 | 1.32k | if( p_sys->p_page ) |
1643 | 210 | { |
1644 | 210 | if( p_sys->p_page->i_region_defs ) |
1645 | 209 | free( p_sys->p_page->p_region_defs ); |
1646 | 210 | free( p_sys->p_page ); |
1647 | 210 | } |
1648 | 1.32k | p_sys->p_page = NULL; |
1649 | 1.32k | } |
1650 | | |
1651 | | static subpicture_t *render( decoder_t *p_dec ) |
1652 | 106 | { |
1653 | 106 | decoder_sys_t *p_sys = p_dec->p_sys; |
1654 | 106 | subpicture_t *p_spu; |
1655 | 106 | int i, j; |
1656 | 106 | int i_base_x; |
1657 | 106 | int i_base_y; |
1658 | | |
1659 | 106 | if ( p_sys->p_page == NULL) |
1660 | 0 | { |
1661 | 0 | return NULL; |
1662 | 0 | } |
1663 | | |
1664 | | /* Allocate the subpicture internal data. */ |
1665 | 106 | p_spu = decoder_NewSubpicture( p_dec, NULL ); |
1666 | 106 | if( !p_spu ) |
1667 | 0 | return NULL; |
1668 | | |
1669 | | /* Set the pf_render callback */ |
1670 | 106 | p_spu->i_start = p_sys->i_pts; |
1671 | | //p_spu->i_stop = (vlc_tick_t) 0; |
1672 | 106 | p_spu->b_ephemer = true; |
1673 | | //p_spu->b_fade = true; |
1674 | | //p_spu->i_stop = p_spu->i_start + (vlc_tick_t) (i_timeout * 1000000); |
1675 | 106 | p_spu->b_subtitle = true; |
1676 | | |
1677 | | /* Correct positioning of SPU */ |
1678 | 106 | i_base_x = p_sys->i_spu_x; |
1679 | 106 | i_base_y = p_sys->i_spu_y; |
1680 | | |
1681 | 106 | p_spu->i_original_picture_width = (unsigned)p_sys->display.i_width_minus1 + 1; |
1682 | 106 | p_spu->i_original_picture_height = (unsigned)p_sys->display.i_height_minus1 + 1; |
1683 | | |
1684 | 106 | if( p_sys->display.b_windowed ) |
1685 | 0 | { |
1686 | | /* From en_300743v01 - */ |
1687 | | /* the DDS is there to indicate intended size/position of text */ |
1688 | | /* the intended video area is ->i_width/height */ |
1689 | | /* the window is within this... SO... we should leave i_original_picture_width etc. as is */ |
1690 | | /* and ONLY change i_base_x. effectively i_max_x/y are only there to limit memory requirements*/ |
1691 | | /* we COULD use the upper limits to limit rendering to within these? */ |
1692 | | |
1693 | | /* see notes on DDS at the top of the file */ |
1694 | 0 | i_base_x += p_sys->display.i_x; |
1695 | 0 | i_base_y += p_sys->display.i_y; |
1696 | 0 | } |
1697 | | |
1698 | | /* Loop on region definitions */ |
1699 | | #ifdef DEBUG_DVBSUB |
1700 | | msg_Dbg( p_dec, "rendering %i regions", p_sys->p_page->i_region_defs ); |
1701 | | #endif |
1702 | | |
1703 | 260 | for( i = 0; i < p_sys->p_page->i_region_defs; i++ ) |
1704 | 154 | { |
1705 | 154 | dvbsub_region_t *p_region; |
1706 | 154 | dvbsub_regiondef_t *p_regiondef; |
1707 | 154 | dvbsub_clut_t *p_clut; |
1708 | 154 | dvbsub_color_t *p_color; |
1709 | 154 | subpicture_region_t *p_spu_region; |
1710 | 154 | uint8_t *p_src, *p_dst; |
1711 | 154 | video_format_t fmt; |
1712 | 154 | video_palette_t palette; |
1713 | 154 | int i_pitch; |
1714 | | |
1715 | 154 | p_regiondef = &p_sys->p_page->p_region_defs[i]; |
1716 | | |
1717 | | /* Find associated region */ |
1718 | 226 | for( p_region = p_sys->p_regions; p_region != NULL; |
1719 | 154 | p_region = p_region->p_next ) |
1720 | 112 | { |
1721 | 112 | if( p_regiondef->i_id == p_region->i_id ) break; |
1722 | 112 | } |
1723 | | |
1724 | | #ifdef DEBUG_DVBSUB |
1725 | | /* if a region exists, then print it's size */ |
1726 | | if (p_region) |
1727 | | { |
1728 | | msg_Dbg( p_dec, "rendering region %i (%i,%i) to (%i,%i)", i, |
1729 | | p_regiondef->i_x, p_regiondef->i_y, |
1730 | | p_regiondef->i_x + p_region->i_width, |
1731 | | p_regiondef->i_y + p_region->i_height ); |
1732 | | } |
1733 | | else |
1734 | | { |
1735 | | msg_Dbg( p_dec, "rendering region %i (%i,%i) (no region matched to render)", i, |
1736 | | p_regiondef->i_x, p_regiondef->i_y ); |
1737 | | } |
1738 | | #endif |
1739 | | |
1740 | 154 | if( !p_region || !p_region->p_pixbuf ) |
1741 | 114 | { |
1742 | 114 | msg_Dbg( p_dec, "region %i not found or invalid", p_regiondef->i_id ); |
1743 | 114 | continue; |
1744 | 114 | } |
1745 | | |
1746 | | /* Find associated CLUT */ |
1747 | 72 | for( p_clut = p_sys->p_cluts; p_clut != NULL; p_clut = p_clut->p_next ) |
1748 | 64 | { |
1749 | 64 | if( p_region->i_clut == p_clut->i_id ) break; |
1750 | 64 | } |
1751 | 40 | if( !p_clut ) |
1752 | 8 | { |
1753 | 8 | msg_Dbg( p_dec, "clut %i not found", p_region->i_clut ); |
1754 | 8 | continue; |
1755 | 8 | } |
1756 | | |
1757 | | /* FIXME: don't create a subpicture region with VLC CODEC YUVP |
1758 | | * when it actually is a TEXT region */ |
1759 | | |
1760 | | /* Create new SPU region */ |
1761 | 32 | video_format_Init( &fmt, VLC_CODEC_YUVP ); |
1762 | 32 | fmt.i_sar_num = 0; /* 0 means use aspect ratio of background video */ |
1763 | 32 | fmt.i_sar_den = 1; |
1764 | 32 | fmt.i_width = fmt.i_visible_width = p_region->i_width; |
1765 | 32 | fmt.i_height = fmt.i_visible_height = p_region->i_height; |
1766 | 32 | fmt.i_x_offset = fmt.i_y_offset = 0; |
1767 | 32 | fmt.p_palette = &palette; |
1768 | 32 | fmt.p_palette->i_entries = ( p_region->i_depth == 1 ) ? 4 : |
1769 | 32 | ( ( p_region->i_depth == 2 ) ? 16 : p_clut->c_8b_entries ); |
1770 | 32 | p_color = ( p_region->i_depth == 1 ) ? p_clut->c_2b : |
1771 | 32 | ( ( p_region->i_depth == 2 ) ? p_clut->c_4b : p_clut->c_8b ); |
1772 | 8.22k | for( j = 0; j < fmt.p_palette->i_entries; j++ ) |
1773 | 8.19k | { |
1774 | 8.19k | fmt.p_palette->palette[j][0] = p_color[j].Y; |
1775 | 8.19k | fmt.p_palette->palette[j][1] = p_color[j].Cb; /* U == Cb */ |
1776 | 8.19k | fmt.p_palette->palette[j][2] = p_color[j].Cr; /* V == Cr */ |
1777 | 8.19k | fmt.p_palette->palette[j][3] = 0xff - p_color[j].T; |
1778 | 8.19k | } |
1779 | 32 | switch (p_clut->dynamic_range_and_colour_gamut) |
1780 | 32 | { |
1781 | 32 | case DVBSUB_ST_COLORIMETRY_CDS: |
1782 | 32 | fmt.space = COLOR_SPACE_BT601; |
1783 | 32 | fmt.primaries = COLOR_PRIMARIES_BT601_525; |
1784 | 32 | fmt.transfer = TRANSFER_FUNC_BT709; |
1785 | 32 | break; |
1786 | 0 | case DVBSUB_ST_COLORIMETRY_SDR_709: |
1787 | 0 | fmt.space = COLOR_SPACE_BT709; |
1788 | 0 | fmt.primaries = COLOR_PRIMARIES_BT709; |
1789 | 0 | fmt.transfer = TRANSFER_FUNC_BT709; |
1790 | 0 | break; |
1791 | 0 | case DVBSUB_ST_COLORIMETRY_SDR_2020: |
1792 | 0 | fmt.space = COLOR_SPACE_BT2020; |
1793 | 0 | fmt.primaries = COLOR_PRIMARIES_BT2020; |
1794 | 0 | fmt.transfer = TRANSFER_FUNC_BT709; |
1795 | 0 | break; |
1796 | 0 | case DVBSUB_ST_COLORIMETRY_HDR_PQ: |
1797 | 0 | fmt.space = COLOR_SPACE_BT2020; |
1798 | 0 | fmt.primaries = COLOR_PRIMARIES_BT2020; |
1799 | 0 | fmt.transfer = TRANSFER_FUNC_SMPTE_ST2084; |
1800 | 0 | break; |
1801 | 0 | case DVBSUB_ST_COLORIMETRY_HDR_HLG: |
1802 | 0 | fmt.space = COLOR_SPACE_BT2020; |
1803 | 0 | fmt.primaries = COLOR_PRIMARIES_BT2020; |
1804 | 0 | fmt.transfer = TRANSFER_FUNC_HLG; |
1805 | 0 | break; |
1806 | 32 | } |
1807 | 32 | fmt.color_range = p_clut->color_range; |
1808 | | |
1809 | 32 | p_spu_region = subpicture_region_New( &fmt ); |
1810 | 32 | fmt.p_palette = NULL; /* was stack var */ |
1811 | 32 | video_format_Clean( &fmt ); |
1812 | 32 | if( !p_spu_region ) |
1813 | 0 | { |
1814 | 0 | msg_Err( p_dec, "cannot allocate SPU region" ); |
1815 | 0 | continue; |
1816 | 0 | } |
1817 | 32 | p_spu_region->b_absolute = true; p_spu_region->b_in_window = false; |
1818 | 32 | p_spu_region->i_x = i_base_x + p_regiondef->i_x; |
1819 | 32 | p_spu_region->i_y = i_base_y + p_regiondef->i_y; |
1820 | 32 | p_spu_region->i_align = p_sys->i_spu_position; |
1821 | 32 | vlc_spu_regions_push(&p_spu->regions, p_spu_region); |
1822 | | |
1823 | 32 | p_src = p_region->p_pixbuf; |
1824 | 32 | p_dst = p_spu_region->p_picture->Y_PIXELS; |
1825 | 32 | i_pitch = p_spu_region->p_picture->Y_PITCH; |
1826 | | |
1827 | | /* Copy pixel buffer */ |
1828 | 42.1k | for( j = 0; j < p_region->i_height; j++ ) |
1829 | 42.0k | { |
1830 | 42.0k | memcpy( p_dst, p_src, p_region->i_width ); |
1831 | 42.0k | p_src += p_region->i_width; |
1832 | 42.0k | p_dst += i_pitch; |
1833 | 42.0k | } |
1834 | | |
1835 | | /* Check subtitles encoded as strings of characters |
1836 | | * (since there are not rendered in the pixbuffer) */ |
1837 | 23.1k | for( j = 0; j < p_region->i_object_defs; j++ ) |
1838 | 23.0k | { |
1839 | 23.0k | dvbsub_objectdef_t *p_object_def = &p_region->p_object_defs[j]; |
1840 | | |
1841 | 23.0k | if( ( p_object_def->i_type != 1 ) || !p_object_def->psz_text ) |
1842 | 23.0k | continue; |
1843 | | |
1844 | | /* Create new SPU region */ |
1845 | 0 | p_spu_region = subpicture_region_NewText(); |
1846 | 0 | if( !p_spu_region ) |
1847 | 0 | { |
1848 | 0 | msg_Err( p_dec, "cannot allocate SPU region" ); |
1849 | 0 | continue; |
1850 | 0 | } |
1851 | | |
1852 | 0 | p_spu_region->fmt.i_sar_num = 1; |
1853 | 0 | p_spu_region->fmt.i_sar_den = 1; |
1854 | 0 | p_spu_region->fmt.i_width = p_spu_region->fmt.i_visible_width = p_region->i_width; |
1855 | 0 | p_spu_region->fmt.i_height = p_spu_region->fmt.i_visible_height = p_region->i_height; |
1856 | |
|
1857 | 0 | p_spu_region->p_text = text_segment_New( p_object_def->psz_text ); |
1858 | 0 | p_spu_region->b_absolute = true; p_spu_region->b_in_window = false; |
1859 | 0 | p_spu_region->i_x = i_base_x + p_regiondef->i_x + p_object_def->i_x; |
1860 | 0 | p_spu_region->i_y = i_base_y + p_regiondef->i_y + p_object_def->i_y; |
1861 | 0 | p_spu_region->i_align = p_sys->i_spu_position; |
1862 | 0 | vlc_spu_regions_push(&p_spu->regions, p_spu_region); |
1863 | 0 | } |
1864 | 32 | } |
1865 | | |
1866 | 106 | return p_spu; |
1867 | 106 | } |
1868 | | |
1869 | | /***************************************************************************** |
1870 | | * encoder_sys_t : encoder descriptor |
1871 | | *****************************************************************************/ |
1872 | | typedef struct encoder_region_t |
1873 | | { |
1874 | | int i_width; |
1875 | | int i_height; |
1876 | | |
1877 | | } encoder_region_t; |
1878 | | |
1879 | | typedef struct |
1880 | | { |
1881 | | unsigned int i_page_ver; |
1882 | | unsigned int i_region_ver; |
1883 | | unsigned int i_clut_ver; |
1884 | | |
1885 | | size_t i_regions; |
1886 | | encoder_region_t *p_regions; |
1887 | | |
1888 | | vlc_tick_t i_pts; |
1889 | | |
1890 | | /* subpicture positioning */ |
1891 | | int i_offset_x; |
1892 | | int i_offset_y; |
1893 | | } encoder_sys_t; |
1894 | | |
1895 | | #ifdef ENABLE_SOUT |
1896 | | static void encode_page_composition( encoder_t *, bs_t *, const subpicture_t * ); |
1897 | | static void encode_clut( encoder_t *, bs_t *, subpicture_region_t * ); |
1898 | | static void encode_region_composition( encoder_t *, bs_t *, const subpicture_t * ); |
1899 | | static void encode_object( encoder_t *, bs_t *, const subpicture_t * ); |
1900 | | |
1901 | | /***************************************************************************** |
1902 | | * OpenEncoder: probe the encoder and return score |
1903 | | *****************************************************************************/ |
1904 | | static int OpenEncoder( vlc_object_t *p_this ) |
1905 | 0 | { |
1906 | 0 | encoder_t *p_enc = (encoder_t *)p_this; |
1907 | 0 | encoder_sys_t *p_sys; |
1908 | |
|
1909 | 0 | if( ( p_enc->fmt_out.i_codec != VLC_CODEC_DVBS ) && |
1910 | 0 | !p_enc->obj.force ) |
1911 | 0 | { |
1912 | 0 | return VLC_EGENERIC; |
1913 | 0 | } |
1914 | | |
1915 | | /* Allocate the memory needed to store the decoder's structure */ |
1916 | 0 | p_sys = malloc(sizeof(encoder_sys_t)); |
1917 | 0 | if (p_sys == NULL) |
1918 | 0 | return VLC_ENOMEM; |
1919 | 0 | p_enc->p_sys = p_sys; |
1920 | |
|
1921 | 0 | p_enc->fmt_out.i_codec = VLC_CODEC_DVBS; |
1922 | 0 | p_enc->fmt_out.subs.dvb.i_id = 1 << 16 | 1; |
1923 | |
|
1924 | 0 | config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); |
1925 | |
|
1926 | 0 | p_sys->i_page_ver = 0; |
1927 | 0 | p_sys->i_region_ver = 0; |
1928 | 0 | p_sys->i_clut_ver = 0; |
1929 | 0 | p_sys->i_regions = 0; |
1930 | 0 | p_sys->p_regions = 0; |
1931 | |
|
1932 | 0 | p_sys->i_offset_x = var_CreateGetInteger( p_this, ENC_CFG_PREFIX "x" ); |
1933 | 0 | p_sys->i_offset_y = var_CreateGetInteger( p_this, ENC_CFG_PREFIX "y" ); |
1934 | |
|
1935 | 0 | static const struct vlc_encoder_operations ops = |
1936 | 0 | { |
1937 | 0 | .close = CloseEncoder, |
1938 | 0 | .encode_sub = Encode, |
1939 | 0 | }; |
1940 | 0 | p_enc->ops = &ops; |
1941 | |
|
1942 | 0 | return VLC_SUCCESS; |
1943 | 0 | } |
1944 | | |
1945 | | /* FIXME: this routine is a hack to convert VLC_CODEC_YUVA |
1946 | | * into VLC_CODEC_YUVP |
1947 | | */ |
1948 | | static void YuvaYuvp( subpicture_t *p_subpic ) |
1949 | 0 | { |
1950 | 0 | const subpicture_region_t *p_region; |
1951 | |
|
1952 | 0 | vlc_spu_regions_foreach_const(p_region, &p_subpic->regions) |
1953 | 0 | { |
1954 | 0 | video_format_t *p_fmt = &p_region->p_picture->format; |
1955 | 0 | int i = 0, j = 0, n = 0, p = 0; |
1956 | 0 | int i_max_entries = 256; |
1957 | |
|
1958 | | #ifdef RANDOM_DITHERING |
1959 | | int i_seed = 0xdeadbeef; /* random seed */ |
1960 | | #else |
1961 | 0 | int *pi_delta; |
1962 | 0 | #endif |
1963 | 0 | int i_pixels = p_region->p_picture->p[0].i_visible_lines |
1964 | 0 | * p_region->p_picture->Y_PITCH; |
1965 | 0 | int i_iterator = p_region->p_picture->p[0].i_visible_lines * 3 / 4 |
1966 | 0 | * p_region->p_picture->Y_PITCH |
1967 | 0 | + p_region->p_picture->Y_PITCH * 1 / 3; |
1968 | 0 | int i_tolerance = 0; |
1969 | |
|
1970 | | #ifdef DEBUG_DVBSUB1 |
1971 | | /* p_enc not valid here */ |
1972 | | msg_Dbg( p_enc, "YuvaYuvp: i_pixels=%d, i_iterator=%d", i_pixels, i_iterator ); |
1973 | | #endif |
1974 | 0 | p_fmt->i_chroma = VLC_CODEC_YUVP; |
1975 | 0 | p_fmt->p_palette = (video_palette_t *) malloc( sizeof( video_palette_t ) ); |
1976 | 0 | if( !p_fmt->p_palette ) break; |
1977 | 0 | p_fmt->p_palette->i_entries = 0; |
1978 | | |
1979 | | /* Find best iterator using Euclide’s algorithm */ |
1980 | 0 | for( ; i_iterator > 1 ; i_iterator-- ) |
1981 | 0 | { |
1982 | 0 | int a = i_pixels; |
1983 | 0 | int b = i_iterator; |
1984 | 0 | int c; |
1985 | |
|
1986 | 0 | while( b ) |
1987 | 0 | { |
1988 | 0 | c = a % b; |
1989 | 0 | a = b; |
1990 | 0 | b = c; |
1991 | 0 | } |
1992 | |
|
1993 | 0 | if( a == 1 ) |
1994 | 0 | { |
1995 | 0 | break; |
1996 | 0 | } |
1997 | 0 | } |
1998 | | |
1999 | | /* Count colors, build best palette */ |
2000 | 0 | for( i_tolerance = 0; i_tolerance < 128; i_tolerance++ ) |
2001 | 0 | { |
2002 | 0 | bool b_success = true; |
2003 | 0 | p_fmt->p_palette->i_entries = 0; |
2004 | |
|
2005 | 0 | for( i = 0; i < i_pixels ; ) |
2006 | 0 | { |
2007 | 0 | uint8_t y, u, v, a; |
2008 | 0 | y = p_region->p_picture->Y_PIXELS[i]; |
2009 | 0 | u = p_region->p_picture->U_PIXELS[i]; |
2010 | 0 | v = p_region->p_picture->V_PIXELS[i]; |
2011 | 0 | a = p_region->p_picture->A_PIXELS[i]; |
2012 | 0 | for( j = 0; j < p_fmt->p_palette->i_entries; j++ ) |
2013 | 0 | { |
2014 | 0 | if( abs((int)p_fmt->p_palette->palette[j][0] - (int)y) <= i_tolerance && |
2015 | 0 | abs((int)p_fmt->p_palette->palette[j][1] - (int)u) <= i_tolerance && |
2016 | 0 | abs((int)p_fmt->p_palette->palette[j][2] - (int)v) <= i_tolerance && |
2017 | 0 | abs((int)p_fmt->p_palette->palette[j][3] - (int)a) <= i_tolerance / 2 ) |
2018 | 0 | { |
2019 | 0 | break; |
2020 | 0 | } |
2021 | 0 | } |
2022 | 0 | if( j == p_fmt->p_palette->i_entries ) |
2023 | 0 | { |
2024 | 0 | p_fmt->p_palette->palette[j][0] = y; |
2025 | 0 | p_fmt->p_palette->palette[j][1] = u; |
2026 | 0 | p_fmt->p_palette->palette[j][2] = v; |
2027 | 0 | p_fmt->p_palette->palette[j][3] = a; |
2028 | 0 | p_fmt->p_palette->i_entries++; |
2029 | 0 | } |
2030 | 0 | if( p_fmt->p_palette->i_entries >= i_max_entries ) |
2031 | 0 | { |
2032 | 0 | b_success = false; |
2033 | 0 | break; |
2034 | 0 | } |
2035 | 0 | i += i_iterator; |
2036 | 0 | if( i > i_pixels ) |
2037 | 0 | { |
2038 | 0 | i -= i_pixels; |
2039 | 0 | } |
2040 | 0 | } |
2041 | |
|
2042 | 0 | if( b_success ) |
2043 | 0 | { |
2044 | 0 | break; |
2045 | 0 | } |
2046 | 0 | } |
2047 | |
|
2048 | | #ifdef DEBUG_DVBSUB1 |
2049 | | /* p_enc not valid here */ |
2050 | | msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries ); |
2051 | | #endif |
2052 | |
|
2053 | 0 | #ifndef RANDOM_DITHERING |
2054 | 0 | pi_delta = calloc( ( p_region->p_picture->Y_PITCH + 1 ) * 4, sizeof(int) ); |
2055 | 0 | if (unlikely(pi_delta == NULL)) |
2056 | 0 | return; |
2057 | 0 | #endif |
2058 | | |
2059 | | /* Fill image with our new colours */ |
2060 | 0 | for( p = 0; p < p_region->p_picture->p[0].i_visible_lines ; p++ ) |
2061 | 0 | { |
2062 | 0 | int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0; |
2063 | |
|
2064 | 0 | for( n = 0; n < p_region->p_picture->Y_PITCH ; n++ ) |
2065 | 0 | { |
2066 | 0 | int i_offset = p * p_region->p_picture->Y_PITCH + n; |
2067 | 0 | int y, u, v, a; |
2068 | 0 | int i_mindist, i_best; |
2069 | |
|
2070 | 0 | y = p_region->p_picture->Y_PIXELS[i_offset]; |
2071 | 0 | u = p_region->p_picture->U_PIXELS[i_offset]; |
2072 | 0 | v = p_region->p_picture->V_PIXELS[i_offset]; |
2073 | 0 | a = p_region->p_picture->A_PIXELS[i_offset]; |
2074 | | |
2075 | | /* Add dithering compensation */ |
2076 | | #ifdef RANDOM_DITHERING |
2077 | | y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80; |
2078 | | u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80; |
2079 | | v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80; |
2080 | | a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80; |
2081 | | #else |
2082 | 0 | y += i_ydelta + pi_delta[ n * 4 + 0 ]; |
2083 | 0 | u += i_udelta + pi_delta[ n * 4 + 1 ]; |
2084 | 0 | v += i_vdelta + pi_delta[ n * 4 + 2 ]; |
2085 | 0 | a += i_adelta + pi_delta[ n * 4 + 3 ]; |
2086 | 0 | #endif |
2087 | | |
2088 | | /* Find best colour in palette */ |
2089 | 0 | for( i_mindist = INT_MAX, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ ) |
2090 | 0 | { |
2091 | 0 | int i_dist = 0; |
2092 | |
|
2093 | 0 | i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y); |
2094 | 0 | i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u); |
2095 | 0 | i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v); |
2096 | 0 | i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a); |
2097 | |
|
2098 | 0 | if( i_dist < i_mindist ) |
2099 | 0 | { |
2100 | 0 | i_mindist = i_dist; |
2101 | 0 | i_best = j; |
2102 | 0 | } |
2103 | 0 | } |
2104 | | |
2105 | | /* Set pixel to best color */ |
2106 | 0 | p_region->p_picture->Y_PIXELS[i_offset] = i_best; |
2107 | | |
2108 | | /* Update dithering state */ |
2109 | | #ifdef RANDOM_DITHERING |
2110 | | i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13); |
2111 | | #else |
2112 | 0 | i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0]; |
2113 | 0 | i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1]; |
2114 | 0 | i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2]; |
2115 | 0 | i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3]; |
2116 | 0 | pi_delta[ n * 4 + 0 ] = i_ydelta * 3 / 8; |
2117 | 0 | pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8; |
2118 | 0 | pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8; |
2119 | 0 | pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8; |
2120 | 0 | i_ydelta = i_ydelta * 5 / 8; |
2121 | 0 | i_udelta = i_udelta * 5 / 8; |
2122 | 0 | i_vdelta = i_vdelta * 5 / 8; |
2123 | 0 | i_adelta = i_adelta * 5 / 8; |
2124 | 0 | #endif |
2125 | 0 | } |
2126 | 0 | } |
2127 | 0 | #ifndef RANDOM_DITHERING |
2128 | 0 | free( pi_delta ); |
2129 | 0 | #endif |
2130 | | |
2131 | | /* pad palette */ |
2132 | 0 | for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ ) |
2133 | 0 | memset(p_fmt->p_palette->palette[i], 0, sizeof(p_fmt->p_palette->palette[i])); |
2134 | 0 | p_fmt->p_palette->i_entries = i_max_entries; |
2135 | | #ifdef DEBUG_DVBSUB1 |
2136 | | /* p_enc not valid here */ |
2137 | | msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries ); |
2138 | | #endif |
2139 | 0 | } |
2140 | 0 | } /* End of hack */ |
2141 | | |
2142 | | /**************************************************************************** |
2143 | | * Encode: the whole thing |
2144 | | ****************************************************************************/ |
2145 | | static block_t *Encode( encoder_t *p_enc, subpicture_t *p_subpic ) |
2146 | 0 | { |
2147 | 0 | subpicture_region_t *p_region = NULL; |
2148 | 0 | bs_t bits, *s = &bits; |
2149 | 0 | block_t *p_block; |
2150 | |
|
2151 | 0 | if( !p_subpic || vlc_spu_regions_is_empty(&p_subpic->regions) ) return NULL; |
2152 | | |
2153 | | /* FIXME: this is a hack to convert VLC_CODEC_YUVA into |
2154 | | * VLC_CODEC_YUVP |
2155 | | */ |
2156 | 0 | p_region = vlc_spu_regions_first_or_null(&p_subpic->regions); |
2157 | | /* Sanity check */ |
2158 | 0 | if( !p_region ) return NULL; |
2159 | | |
2160 | 0 | if( !subpicture_region_IsText( p_region ) ) |
2161 | 0 | { |
2162 | 0 | if( p_region->p_picture->format.i_chroma == VLC_CODEC_YUVA ) |
2163 | 0 | { |
2164 | 0 | YuvaYuvp( p_subpic ); |
2165 | 0 | } |
2166 | |
|
2167 | 0 | if( p_region->p_picture->format.i_chroma != VLC_CODEC_YUVP ) |
2168 | 0 | { |
2169 | 0 | msg_Err( p_enc, "chroma %4.4s not supported", (char *)&p_region->p_picture->format.i_chroma ); |
2170 | 0 | return NULL; |
2171 | 0 | } |
2172 | | |
2173 | 0 | if( p_region->p_picture->format.p_palette ) |
2174 | 0 | { |
2175 | 0 | switch( p_region->p_picture->format.p_palette->i_entries ) |
2176 | 0 | { |
2177 | 0 | case 0: |
2178 | 0 | case 4: |
2179 | 0 | case 16: |
2180 | 0 | case 256: |
2181 | 0 | break; |
2182 | 0 | default: |
2183 | 0 | msg_Err( p_enc, "subpicture palette (%d) not handled", |
2184 | 0 | p_region->p_picture->format.p_palette->i_entries ); |
2185 | 0 | return NULL; |
2186 | 0 | } |
2187 | 0 | } |
2188 | 0 | } |
2189 | | /* End of hack */ |
2190 | | |
2191 | | #ifdef DEBUG_DVBSUB |
2192 | | msg_Dbg( p_enc, "encoding subpicture" ); |
2193 | | #endif |
2194 | 0 | p_block = block_Alloc( 64000 ); |
2195 | 0 | if( unlikely(p_block == NULL) ) |
2196 | 0 | return NULL; |
2197 | | |
2198 | 0 | bs_init( s, p_block->p_buffer, p_block->i_buffer ); |
2199 | |
|
2200 | 0 | bs_write( s, 8, 0x20 ); /* Data identifier */ |
2201 | 0 | bs_write( s, 8, 0x0 ); /* Subtitle stream id */ |
2202 | |
|
2203 | 0 | encode_page_composition( p_enc, s, p_subpic ); |
2204 | 0 | encode_region_composition( p_enc, s, p_subpic ); |
2205 | 0 | encode_clut( p_enc, s, p_region ); |
2206 | 0 | encode_object( p_enc, s, p_subpic ); |
2207 | | |
2208 | | /* End of display */ |
2209 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2210 | 0 | bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */ |
2211 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2212 | 0 | bs_write( s, 16, 0 ); /* Segment length */ |
2213 | |
|
2214 | 0 | bs_write( s, 8, 0xff );/* End marker */ |
2215 | 0 | p_block->i_buffer = bs_pos( s ) / 8; |
2216 | 0 | p_block->i_pts = p_block->i_dts = p_subpic->i_start; |
2217 | 0 | if( !p_subpic->b_ephemer && |
2218 | 0 | ( p_subpic->i_stop != VLC_TICK_INVALID && p_subpic->i_stop > p_subpic->i_start ) ) |
2219 | 0 | { |
2220 | 0 | block_t *p_block_stop; |
2221 | |
|
2222 | 0 | p_block->i_length = p_subpic->i_stop - p_subpic->i_start; |
2223 | | |
2224 | | /* Send another (empty) subtitle to signal the end of display */ |
2225 | 0 | p_block_stop = block_Alloc( 64000 ); |
2226 | 0 | if( unlikely(p_block_stop == NULL) ) |
2227 | 0 | { |
2228 | 0 | block_Release(p_block); |
2229 | 0 | return NULL; |
2230 | 0 | } |
2231 | | |
2232 | 0 | bs_init( s, p_block_stop->p_buffer, p_block_stop->i_buffer ); |
2233 | 0 | bs_write( s, 8, 0x20 ); /* Data identifier */ |
2234 | 0 | bs_write( s, 8, 0x0 ); /* Subtitle stream id */ |
2235 | 0 | encode_page_composition( p_enc, s, 0 ); |
2236 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2237 | 0 | bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */ |
2238 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2239 | 0 | bs_write( s, 16, 0 ); /* Segment length */ |
2240 | 0 | bs_write( s, 8, 0xff );/* End marker */ |
2241 | 0 | p_block_stop->i_buffer = bs_pos( s ) / 8; |
2242 | 0 | p_block_stop->i_pts = p_block_stop->i_dts = p_subpic->i_stop; |
2243 | 0 | block_ChainAppend( &p_block, p_block_stop ); |
2244 | 0 | p_block_stop->i_length = VLC_TICK_FROM_MS(100); /* p_subpic->i_stop - p_subpic->i_start; */ |
2245 | 0 | } |
2246 | | #ifdef DEBUG_DVBSUB |
2247 | | msg_Dbg( p_enc, "subpicture encoded properly" ); |
2248 | | #endif |
2249 | 0 | return p_block; |
2250 | 0 | } |
2251 | | |
2252 | | /***************************************************************************** |
2253 | | * CloseEncoder: encoder destruction |
2254 | | *****************************************************************************/ |
2255 | | static void CloseEncoder( encoder_t *p_enc ) |
2256 | 0 | { |
2257 | 0 | encoder_sys_t *p_sys = p_enc->p_sys; |
2258 | |
|
2259 | 0 | var_Destroy( p_enc , ENC_CFG_PREFIX "x" ); |
2260 | 0 | var_Destroy( p_enc , ENC_CFG_PREFIX "y" ); |
2261 | |
|
2262 | 0 | if( p_sys->i_regions ) free( p_sys->p_regions ); |
2263 | 0 | free( p_sys ); |
2264 | 0 | } |
2265 | | |
2266 | | static void encode_page_composition( encoder_t *p_enc, bs_t *s, |
2267 | | const subpicture_t *p_subpic ) |
2268 | 0 | { |
2269 | 0 | encoder_sys_t *p_sys = p_enc->p_sys; |
2270 | 0 | const subpicture_region_t *p_region; |
2271 | 0 | bool b_mode_change = false; |
2272 | 0 | unsigned int i_regions; |
2273 | 0 | int i_timeout; |
2274 | |
|
2275 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2276 | 0 | bs_write( s, 8, DVBSUB_ST_PAGE_COMPOSITION ); /* Segment type */ |
2277 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2278 | |
|
2279 | 0 | i_regions = 0; |
2280 | 0 | if (p_subpic) |
2281 | 0 | vlc_spu_regions_foreach_const(p_region, &p_subpic->regions) |
2282 | 0 | { |
2283 | 0 | if( i_regions >= p_sys->i_regions ) |
2284 | 0 | { |
2285 | 0 | encoder_region_t region; |
2286 | 0 | region.i_width = region.i_height = 0; |
2287 | 0 | p_sys->p_regions = xrealloc( p_sys->p_regions, |
2288 | 0 | sizeof(encoder_region_t) * (p_sys->i_regions + 1) ); |
2289 | 0 | p_sys->p_regions[p_sys->i_regions++] = region; |
2290 | 0 | } |
2291 | |
|
2292 | 0 | if( ( p_sys->p_regions[i_regions].i_width < |
2293 | 0 | (int)p_region->fmt.i_visible_width ) || |
2294 | 0 | ( p_sys->p_regions[i_regions].i_width > |
2295 | 0 | (int)p_region->fmt.i_visible_width ) ) |
2296 | 0 | { |
2297 | 0 | b_mode_change = true; |
2298 | 0 | msg_Dbg( p_enc, "region %u width change: %i -> %i", |
2299 | 0 | i_regions, p_sys->p_regions[i_regions].i_width, |
2300 | 0 | p_region->fmt.i_visible_width ); |
2301 | 0 | p_sys->p_regions[i_regions].i_width = |
2302 | 0 | p_region->fmt.i_visible_width; |
2303 | 0 | } |
2304 | 0 | if( p_sys->p_regions[i_regions].i_height < |
2305 | 0 | (int)p_region->fmt.i_visible_height ) |
2306 | 0 | { |
2307 | 0 | b_mode_change = true; |
2308 | 0 | msg_Dbg( p_enc, "region %u height change: %i -> %i", |
2309 | 0 | i_regions, p_sys->p_regions[i_regions].i_height, |
2310 | 0 | p_region->fmt.i_visible_height ); |
2311 | 0 | p_sys->p_regions[i_regions].i_height = |
2312 | 0 | p_region->fmt.i_visible_height; |
2313 | 0 | } |
2314 | 0 | i_regions++; |
2315 | 0 | } |
2316 | |
|
2317 | 0 | bs_write( s, 16, i_regions * 6 + 2 ); /* Segment length */ |
2318 | |
|
2319 | 0 | i_timeout = 0; |
2320 | 0 | if( p_subpic && !p_subpic->b_ephemer && |
2321 | 0 | ( p_subpic->i_stop != VLC_TICK_INVALID && p_subpic->i_stop > p_subpic->i_start ) ) |
2322 | 0 | { |
2323 | 0 | i_timeout = SEC_FROM_VLC_TICK(p_subpic->i_stop - p_subpic->i_start); |
2324 | 0 | } |
2325 | |
|
2326 | 0 | bs_write( s, 8, i_timeout ); /* Timeout */ |
2327 | 0 | bs_write( s, 4, p_sys->i_page_ver++ ); |
2328 | 0 | bs_write( s, 2, b_mode_change ? |
2329 | 0 | DVBSUB_PCS_STATE_CHANGE : DVBSUB_PCS_STATE_ACQUISITION ); |
2330 | 0 | bs_write( s, 2, 0 ); /* Reserved */ |
2331 | |
|
2332 | 0 | i_regions = 0; |
2333 | 0 | if (p_subpic) |
2334 | 0 | vlc_spu_regions_foreach_const(p_region, &p_subpic->regions) |
2335 | 0 | { |
2336 | 0 | bs_write( s, 8, i_regions ); |
2337 | 0 | bs_write( s, 8, 0 ); /* Reserved */ |
2338 | 0 | if( (p_sys->i_offset_x > 0) && (p_sys->i_offset_y > 0) ) |
2339 | 0 | { |
2340 | 0 | bs_write( s, 16, p_sys->i_offset_x ); /* override x position */ |
2341 | 0 | bs_write( s, 16, p_sys->i_offset_y ); /* override y position */ |
2342 | 0 | } |
2343 | 0 | else |
2344 | 0 | { |
2345 | 0 | bs_write( s, 16, p_region->i_x ); |
2346 | 0 | bs_write( s, 16, p_region->i_y ); |
2347 | 0 | } |
2348 | 0 | i_regions++; |
2349 | 0 | } |
2350 | 0 | } |
2351 | | |
2352 | | static void encode_clut( encoder_t *p_enc, bs_t *s, subpicture_region_t *p_region ) |
2353 | 0 | { |
2354 | 0 | encoder_sys_t *p_sys = p_enc->p_sys; |
2355 | 0 | video_palette_t *p_pal, empty_palette = { .i_entries = 4 }; |
2356 | | |
2357 | | /* Sanity check */ |
2358 | 0 | if( !p_region ) return; |
2359 | | |
2360 | 0 | if( !subpicture_region_IsText( p_region ) && p_region->p_picture->format.i_chroma == VLC_CODEC_YUVP ) |
2361 | 0 | { |
2362 | 0 | p_pal = p_region->p_picture->format.p_palette; |
2363 | 0 | } |
2364 | 0 | else |
2365 | 0 | p_pal = &empty_palette; |
2366 | |
|
2367 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2368 | 0 | bs_write( s, 8, DVBSUB_ST_CLUT_DEFINITION ); /* Segment type */ |
2369 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2370 | |
|
2371 | 0 | bs_write( s, 16, p_pal->i_entries * 6 + 2 ); /* Segment length */ |
2372 | 0 | bs_write( s, 8, 1 ); /* Clut id */ |
2373 | 0 | bs_write( s, 4, p_sys->i_clut_ver++ ); |
2374 | 0 | bs_write( s, 4, 0 ); /* Reserved */ |
2375 | |
|
2376 | 0 | for( int i = 0; i < p_pal->i_entries; i++ ) |
2377 | 0 | { |
2378 | 0 | bs_write( s, 8, i ); /* Clut entry id */ |
2379 | 0 | bs_write( s, 1, p_pal->i_entries == 4 ); /* 2bit/entry flag */ |
2380 | 0 | bs_write( s, 1, p_pal->i_entries == 16 ); /* 4bit/entry flag */ |
2381 | 0 | bs_write( s, 1, p_pal->i_entries == 256 ); /* 8bit/entry flag */ |
2382 | 0 | bs_write( s, 4, 0 ); /* Reserved */ |
2383 | 0 | bs_write( s, 1, 1 ); /* Full range flag */ |
2384 | 0 | bs_write( s, 8, p_pal->palette[i][3] ? /* Y value */ |
2385 | 0 | (p_pal->palette[i][0] ? p_pal->palette[i][0] : 16) : 0 ); |
2386 | 0 | bs_write( s, 8, p_pal->palette[i][1] ); /* Cr value */ |
2387 | 0 | bs_write( s, 8, p_pal->palette[i][2] ); /* Cb value */ |
2388 | 0 | bs_write( s, 8, 0xff - p_pal->palette[i][3] ); /* T value */ |
2389 | 0 | } |
2390 | 0 | } |
2391 | | |
2392 | | static void encode_region_composition( encoder_t *p_enc, bs_t *s, |
2393 | | const subpicture_t *p_subpic ) |
2394 | 0 | { |
2395 | 0 | encoder_sys_t *p_sys = p_enc->p_sys; |
2396 | 0 | const subpicture_region_t *p_region; |
2397 | 0 | unsigned int i_region; |
2398 | |
|
2399 | 0 | i_region = 0; |
2400 | 0 | vlc_spu_regions_foreach_const(p_region, &p_subpic->regions) |
2401 | 0 | { |
2402 | 0 | int i_entries = 4, i_depth = 0x1, i_bg = 0; |
2403 | 0 | bool b_text = subpicture_region_IsText( p_region ); |
2404 | |
|
2405 | 0 | if( !b_text ) |
2406 | 0 | { |
2407 | 0 | video_palette_t *p_pal = p_region->p_picture->format.p_palette; |
2408 | |
|
2409 | 0 | if( !p_pal ) |
2410 | 0 | { |
2411 | 0 | msg_Err( p_enc, "subpicture has no palette - ignoring it" ); |
2412 | 0 | break; |
2413 | 0 | } |
2414 | | |
2415 | 0 | i_entries = p_pal->i_entries; |
2416 | 0 | i_depth = i_entries == 4 ? 0x1 : i_entries == 16 ? 0x2 : 0x3; |
2417 | |
|
2418 | 0 | for( i_bg = 0; i_bg < p_pal->i_entries; i_bg++ ) |
2419 | 0 | { |
2420 | 0 | if( !p_pal->palette[i_bg][3] ) break; |
2421 | 0 | } |
2422 | 0 | } |
2423 | | |
2424 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2425 | 0 | bs_write( s, 8, DVBSUB_ST_REGION_COMPOSITION ); /* Segment type */ |
2426 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2427 | |
|
2428 | 0 | bs_write( s, 16, 10 + 6 + (b_text ? 2 : 0) ); /* Segment length */ |
2429 | 0 | bs_write( s, 8, i_region ); |
2430 | 0 | bs_write( s, 4, p_sys->i_region_ver++ ); |
2431 | | |
2432 | | /* Region attributes */ |
2433 | 0 | bs_write( s, 1, i_bg < i_entries ); /* Fill */ |
2434 | 0 | bs_write( s, 3, 0 ); /* Reserved */ |
2435 | 0 | bs_write( s, 16, p_sys->p_regions[i_region].i_width ); |
2436 | 0 | bs_write( s, 16, p_sys->p_regions[i_region].i_height ); |
2437 | 0 | bs_write( s, 3, i_depth ); /* Region level of compatibility */ |
2438 | 0 | bs_write( s, 3, i_depth ); /* Region depth */ |
2439 | 0 | bs_write( s, 2, 0 ); /* Reserved */ |
2440 | 0 | bs_write( s, 8, 1 ); /* Clut id */ |
2441 | 0 | bs_write( s, 8, i_bg ); /* region 8bit pixel code */ |
2442 | 0 | bs_write( s, 4, i_bg ); /* region 4bit pixel code */ |
2443 | 0 | bs_write( s, 2, i_bg ); /* region 2bit pixel code */ |
2444 | 0 | bs_write( s, 2, 0 ); /* Reserved */ |
2445 | | |
2446 | | /* In our implementation we only have 1 object per region */ |
2447 | 0 | bs_write( s, 16, i_region ); |
2448 | 0 | bs_write( s, 2, b_text ? DVBSUB_OT_BASIC_CHAR:DVBSUB_OT_BASIC_BITMAP ); |
2449 | 0 | bs_write( s, 2, 0 ); /* object provider flag */ |
2450 | 0 | bs_write( s, 12, 0 );/* object horizontal position */ |
2451 | 0 | bs_write( s, 4, 0 ); /* Reserved */ |
2452 | 0 | bs_write( s, 12, 0 );/* object vertical position */ |
2453 | |
|
2454 | 0 | if( b_text ) |
2455 | 0 | { |
2456 | 0 | bs_write( s, 8, 1 ); /* foreground pixel code */ |
2457 | 0 | bs_write( s, 8, 0 ); /* background pixel code */ |
2458 | 0 | } |
2459 | 0 | i_region++; |
2460 | 0 | } |
2461 | 0 | } |
2462 | | |
2463 | | static void encode_pixel_data( encoder_t *p_enc, bs_t *s, |
2464 | | const subpicture_region_t *p_region, |
2465 | | bool b_top ); |
2466 | | |
2467 | | static void encode_object( encoder_t *p_enc, bs_t *s, const subpicture_t *p_subpic ) |
2468 | 0 | { |
2469 | 0 | encoder_sys_t *p_sys = p_enc->p_sys; |
2470 | 0 | const subpicture_region_t *p_region; |
2471 | 0 | int i_region; |
2472 | |
|
2473 | 0 | int i_length_pos, i_update_pos, i_pixel_data_pos; |
2474 | |
|
2475 | 0 | i_region = 0; |
2476 | 0 | vlc_spu_regions_foreach_const(p_region, &p_subpic->regions) |
2477 | 0 | { |
2478 | 0 | bs_write( s, 8, 0x0f ); /* Sync byte */ |
2479 | 0 | bs_write( s, 8, DVBSUB_ST_OBJECT_DATA ); /* Segment type */ |
2480 | 0 | bs_write( s, 16, 1 ); /* Page id */ |
2481 | |
|
2482 | 0 | i_length_pos = bs_pos( s ); |
2483 | 0 | bs_write( s, 16, 0 ); /* Segment length */ |
2484 | 0 | bs_write( s, 16, i_region ); /* Object id */ |
2485 | 0 | bs_write( s, 4, p_sys->i_region_ver++ ); |
2486 | | |
2487 | | /* object coding method */ |
2488 | 0 | if (subpicture_region_IsText( p_region )) |
2489 | 0 | bs_write( s, 2, 1 ); |
2490 | 0 | else if ( p_region->p_picture->format.i_chroma == VLC_CODEC_YUVP ) |
2491 | 0 | bs_write( s, 2, 0 ); |
2492 | 0 | else |
2493 | 0 | { |
2494 | 0 | msg_Err( p_enc, "FOURCC %4.4s not supported by encoder.", |
2495 | 0 | (const char*)&p_region->p_picture->format.i_chroma ); |
2496 | 0 | i_region++; |
2497 | 0 | continue; |
2498 | 0 | } |
2499 | | |
2500 | 0 | bs_write( s, 1, 0 ); /* non modifying color flag */ |
2501 | 0 | bs_write( s, 1, 0 ); /* Reserved */ |
2502 | |
|
2503 | 0 | if(subpicture_region_IsText( p_region )) |
2504 | 0 | { |
2505 | 0 | int i_size, i; |
2506 | |
|
2507 | 0 | if( !p_region->p_text ) |
2508 | 0 | { |
2509 | 0 | i_region++; |
2510 | 0 | continue; |
2511 | 0 | } |
2512 | | |
2513 | 0 | i_size = __MIN( strlen( p_region->p_text->psz_text ), 256 ); |
2514 | |
|
2515 | 0 | bs_write( s, 8, i_size ); /* number of characters in string */ |
2516 | 0 | for( i = 0; i < i_size; i++ ) |
2517 | 0 | { |
2518 | 0 | bs_write( s, 16, p_region->p_text->psz_text[i] ); |
2519 | 0 | } |
2520 | | |
2521 | | /* Update segment length */ |
2522 | 0 | SetWBE( &s->p_start[i_length_pos/8], |
2523 | 0 | (bs_pos(s) - i_length_pos)/8 -2 ); |
2524 | 0 | i_region++; |
2525 | 0 | continue; |
2526 | 0 | } |
2527 | | |
2528 | | /* Coding of a bitmap object */ |
2529 | 0 | i_update_pos = bs_pos( s ); |
2530 | 0 | bs_write( s, 16, 0 ); /* topfield data block length */ |
2531 | 0 | bs_write( s, 16, 0 ); /* bottomfield data block length */ |
2532 | | |
2533 | | /* Top field */ |
2534 | 0 | i_pixel_data_pos = bs_pos( s ); |
2535 | 0 | encode_pixel_data( p_enc, s, p_region, true ); |
2536 | 0 | i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8; |
2537 | 0 | SetWBE( &s->p_start[i_update_pos/8], i_pixel_data_pos ); |
2538 | | |
2539 | | /* Bottom field */ |
2540 | 0 | i_pixel_data_pos = bs_pos( s ); |
2541 | 0 | encode_pixel_data( p_enc, s, p_region, false ); |
2542 | 0 | i_pixel_data_pos = ( bs_pos( s ) - i_pixel_data_pos ) / 8; |
2543 | 0 | SetWBE( &s->p_start[i_update_pos/8+2], i_pixel_data_pos ); |
2544 | | |
2545 | | /* Stuffing for word alignment */ |
2546 | 0 | bs_align_0( s ); |
2547 | 0 | if( bs_pos( s ) % 16 ) bs_write( s, 8, 0 ); |
2548 | | |
2549 | | /* Update segment length */ |
2550 | 0 | SetWBE( &s->p_start[i_length_pos/8], (bs_pos(s) - i_length_pos)/8 -2 ); |
2551 | 0 | i_region++; |
2552 | 0 | } |
2553 | 0 | } |
2554 | | |
2555 | | static void encode_pixel_line_2bp( bs_t *s, const subpicture_region_t *p_region, |
2556 | | int i_line ); |
2557 | | static void encode_pixel_line_4bp( bs_t *s, const subpicture_region_t *p_region, |
2558 | | int i_line ); |
2559 | | static void encode_pixel_line_8bp( bs_t *s, const subpicture_region_t *p_region, |
2560 | | int i_line ); |
2561 | | static void encode_pixel_data( encoder_t *p_enc, bs_t *s, |
2562 | | const subpicture_region_t *p_region, |
2563 | | bool b_top ) |
2564 | 0 | { |
2565 | 0 | unsigned int i_line; |
2566 | | |
2567 | | /* Encode line by line */ |
2568 | 0 | for( i_line = !b_top; i_line < p_region->fmt.i_visible_height; |
2569 | 0 | i_line += 2 ) |
2570 | 0 | { |
2571 | 0 | switch( p_region->p_picture->format.p_palette->i_entries ) |
2572 | 0 | { |
2573 | 0 | case 0: |
2574 | 0 | break; |
2575 | | |
2576 | 0 | case 4: |
2577 | 0 | bs_write( s, 8, 0x10 ); /* 2 bit/pixel code string */ |
2578 | 0 | encode_pixel_line_2bp( s, p_region, i_line ); |
2579 | 0 | break; |
2580 | | |
2581 | 0 | case 16: |
2582 | 0 | bs_write( s, 8, 0x11 ); /* 4 bit/pixel code string */ |
2583 | 0 | encode_pixel_line_4bp( s, p_region, i_line ); |
2584 | 0 | break; |
2585 | | |
2586 | 0 | case 256: |
2587 | 0 | bs_write( s, 8, 0x12 ); /* 8 bit/pixel code string */ |
2588 | 0 | encode_pixel_line_8bp( s, p_region, i_line ); |
2589 | 0 | break; |
2590 | | |
2591 | 0 | default: |
2592 | 0 | msg_Err( p_enc, "subpicture palette (%i) not handled", |
2593 | 0 | p_region->p_picture->format.p_palette->i_entries ); |
2594 | 0 | break; |
2595 | 0 | } |
2596 | | |
2597 | 0 | bs_write( s, 8, 0xf0 ); /* End of object line code */ |
2598 | 0 | } |
2599 | 0 | } |
2600 | | |
2601 | | static void encode_pixel_line_2bp( bs_t *s, const subpicture_region_t *p_region, |
2602 | | int i_line ) |
2603 | 0 | { |
2604 | 0 | unsigned int i, i_length = 0; |
2605 | 0 | int i_pitch = p_region->p_picture->p->i_pitch; |
2606 | 0 | uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ]; |
2607 | 0 | int i_last_pixel = p_data[0]; |
2608 | |
|
2609 | 0 | for( i = 0; i <= p_region->fmt.i_visible_width; i++ ) |
2610 | 0 | { |
2611 | 0 | if( ( i != p_region->fmt.i_visible_width ) && |
2612 | 0 | ( p_data[i] == i_last_pixel ) && ( i_length != 284 ) ) |
2613 | 0 | { |
2614 | 0 | i_length++; |
2615 | 0 | continue; |
2616 | 0 | } |
2617 | | |
2618 | 0 | if( ( i_length == 1 ) || ( i_length == 11 ) || ( i_length == 28 ) ) |
2619 | 0 | { |
2620 | | /* 2bit/pixel code */ |
2621 | 0 | if( i_last_pixel ) |
2622 | 0 | bs_write( s, 2, i_last_pixel ); |
2623 | 0 | else |
2624 | 0 | { |
2625 | 0 | bs_write( s, 2, 0 ); |
2626 | 0 | bs_write( s, 1, 0 ); |
2627 | 0 | bs_write( s, 1, 1 ); /* pseudo color 0 */ |
2628 | 0 | } |
2629 | 0 | i_length--; |
2630 | 0 | } |
2631 | |
|
2632 | 0 | if( i_length == 2 ) |
2633 | 0 | { |
2634 | 0 | if( i_last_pixel ) |
2635 | 0 | { |
2636 | 0 | bs_write( s, 2, i_last_pixel ); |
2637 | 0 | bs_write( s, 2, i_last_pixel ); |
2638 | 0 | } |
2639 | 0 | else |
2640 | 0 | { |
2641 | 0 | bs_write( s, 2, 0 ); |
2642 | 0 | bs_write( s, 1, 0 ); |
2643 | 0 | bs_write( s, 1, 0 ); |
2644 | 0 | bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */ |
2645 | 0 | } |
2646 | 0 | } |
2647 | 0 | else if( i_length > 2 ) |
2648 | 0 | { |
2649 | 0 | bs_write( s, 2, 0 ); |
2650 | 0 | if( i_length <= 10 ) |
2651 | 0 | { |
2652 | 0 | bs_write( s, 1, 1 ); |
2653 | 0 | bs_write( s, 3, i_length - 3 ); |
2654 | 0 | bs_write( s, 2, i_last_pixel ); |
2655 | 0 | } |
2656 | 0 | else |
2657 | 0 | { |
2658 | 0 | bs_write( s, 1, 0 ); |
2659 | 0 | bs_write( s, 1, 0 ); |
2660 | |
|
2661 | 0 | if( i_length <= 27 ) |
2662 | 0 | { |
2663 | 0 | bs_write( s, 2, 2 ); |
2664 | 0 | bs_write( s, 4, i_length - 12 ); |
2665 | 0 | bs_write( s, 2, i_last_pixel ); |
2666 | 0 | } |
2667 | 0 | else |
2668 | 0 | { |
2669 | 0 | bs_write( s, 2, 3 ); |
2670 | 0 | bs_write( s, 8, i_length - 29 ); |
2671 | 0 | bs_write( s, 2, i_last_pixel ); |
2672 | 0 | } |
2673 | 0 | } |
2674 | 0 | } |
2675 | |
|
2676 | 0 | if( i == p_region->fmt.i_visible_width ) break; |
2677 | | |
2678 | 0 | i_last_pixel = p_data[i]; |
2679 | 0 | i_length = 1; |
2680 | 0 | } |
2681 | | |
2682 | | /* Stop */ |
2683 | 0 | bs_write( s, 2, 0 ); |
2684 | 0 | bs_write( s, 1, 0 ); |
2685 | 0 | bs_write( s, 1, 0 ); |
2686 | 0 | bs_write( s, 2, 0 ); |
2687 | | |
2688 | | /* Stuffing */ |
2689 | 0 | bs_align_0( s ); |
2690 | 0 | } |
2691 | | |
2692 | | static void encode_pixel_line_4bp( bs_t *s, const subpicture_region_t *p_region, |
2693 | | int i_line ) |
2694 | 0 | { |
2695 | 0 | unsigned int i, i_length = 0; |
2696 | 0 | int i_pitch = p_region->p_picture->p->i_pitch; |
2697 | 0 | uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ]; |
2698 | 0 | int i_last_pixel = p_data[0]; |
2699 | |
|
2700 | 0 | for( i = 0; i <= p_region->fmt.i_visible_width; i++ ) |
2701 | 0 | { |
2702 | 0 | if( i != p_region->fmt.i_visible_width && |
2703 | 0 | p_data[i] == i_last_pixel && i_length != 280 ) |
2704 | 0 | { |
2705 | 0 | i_length++; |
2706 | 0 | continue; |
2707 | 0 | } |
2708 | | |
2709 | 0 | if( ( i_length == 1 ) || |
2710 | 0 | ( ( i_length == 3 ) && i_last_pixel ) || |
2711 | 0 | ( i_length == 8 ) ) |
2712 | 0 | { |
2713 | | /* 4bit/pixel code */ |
2714 | 0 | if( i_last_pixel ) |
2715 | 0 | bs_write( s, 4, i_last_pixel ); |
2716 | 0 | else |
2717 | 0 | { |
2718 | 0 | bs_write( s, 4, 0 ); |
2719 | 0 | bs_write( s, 1, 1 ); |
2720 | 0 | bs_write( s, 1, 1 ); |
2721 | 0 | bs_write( s, 2, 0 ); /* pseudo color 0 */ |
2722 | 0 | } |
2723 | 0 | i_length--; |
2724 | 0 | } |
2725 | |
|
2726 | 0 | if( i_length == 2 ) |
2727 | 0 | { |
2728 | 0 | if( i_last_pixel ) |
2729 | 0 | { |
2730 | 0 | bs_write( s, 4, i_last_pixel ); |
2731 | 0 | bs_write( s, 4, i_last_pixel ); |
2732 | 0 | } |
2733 | 0 | else |
2734 | 0 | { |
2735 | 0 | bs_write( s, 4, 0 ); |
2736 | 0 | bs_write( s, 1, 1 ); |
2737 | 0 | bs_write( s, 1, 1 ); |
2738 | 0 | bs_write( s, 2, 1 ); /* 2 * pseudo color 0 */ |
2739 | 0 | } |
2740 | 0 | } |
2741 | 0 | else if( !i_last_pixel && ( i_length >= 3 ) && ( i_length <= 9 ) ) |
2742 | 0 | { |
2743 | 0 | bs_write( s, 4, 0 ); |
2744 | 0 | bs_write( s, 1, 0 ); |
2745 | 0 | bs_write( s, 3, i_length - 2 ); /* (i_length - 2) * color 0 */ |
2746 | 0 | } |
2747 | 0 | else if( i_length > 2 ) |
2748 | 0 | { |
2749 | 0 | bs_write( s, 4, 0 ); |
2750 | 0 | bs_write( s, 1, 1 ); |
2751 | |
|
2752 | 0 | if( i_length <= 7 ) |
2753 | 0 | { |
2754 | 0 | bs_write( s, 1, 0 ); |
2755 | 0 | bs_write( s, 2, i_length - 4 ); |
2756 | 0 | bs_write( s, 4, i_last_pixel ); |
2757 | 0 | } |
2758 | 0 | else |
2759 | 0 | { |
2760 | 0 | bs_write( s, 1, 1 ); |
2761 | |
|
2762 | 0 | if( i_length <= 24 ) |
2763 | 0 | { |
2764 | 0 | bs_write( s, 2, 2 ); |
2765 | 0 | bs_write( s, 4, i_length - 9 ); |
2766 | 0 | bs_write( s, 4, i_last_pixel ); |
2767 | 0 | } |
2768 | 0 | else |
2769 | 0 | { |
2770 | 0 | bs_write( s, 2, 3 ); |
2771 | 0 | bs_write( s, 8, i_length - 25 ); |
2772 | 0 | bs_write( s, 4, i_last_pixel ); |
2773 | 0 | } |
2774 | 0 | } |
2775 | 0 | } |
2776 | |
|
2777 | 0 | if( i == p_region->fmt.i_visible_width ) break; |
2778 | | |
2779 | 0 | i_last_pixel = p_data[i]; |
2780 | 0 | i_length = 1; |
2781 | 0 | } |
2782 | | |
2783 | | /* Stop */ |
2784 | 0 | bs_write( s, 8, 0 ); |
2785 | | |
2786 | | /* Stuffing */ |
2787 | 0 | bs_align_0( s ); |
2788 | 0 | } |
2789 | | |
2790 | | static void encode_pixel_line_8bp( bs_t *s, const subpicture_region_t *p_region, |
2791 | | int i_line ) |
2792 | 0 | { |
2793 | 0 | unsigned int i, i_length = 0; |
2794 | 0 | int i_pitch = p_region->p_picture->p->i_pitch; |
2795 | 0 | uint8_t *p_data = &p_region->p_picture->p->p_pixels[ i_pitch * i_line ]; |
2796 | 0 | int i_last_pixel = p_data[0]; |
2797 | |
|
2798 | 0 | for( i = 0; i <= p_region->fmt.i_visible_width; i++ ) |
2799 | 0 | { |
2800 | 0 | if( ( i != p_region->fmt.i_visible_width ) && |
2801 | 0 | ( p_data[i] == i_last_pixel ) && ( i_length != 127 ) ) |
2802 | 0 | { |
2803 | 0 | i_length++; |
2804 | 0 | continue; |
2805 | 0 | } |
2806 | | |
2807 | 0 | if( ( i_length == 1 ) && i_last_pixel ) |
2808 | 0 | { |
2809 | | /* 8bit/pixel code */ |
2810 | 0 | bs_write( s, 8, i_last_pixel ); |
2811 | 0 | } |
2812 | 0 | else if( ( i_length == 2 ) && i_last_pixel ) |
2813 | 0 | { |
2814 | | /* 8bit/pixel code */ |
2815 | 0 | bs_write( s, 8, i_last_pixel ); |
2816 | 0 | bs_write( s, 8, i_last_pixel ); |
2817 | 0 | } |
2818 | 0 | else if( i_length <= 127 ) |
2819 | 0 | { |
2820 | 0 | bs_write( s, 8, 0 ); |
2821 | |
|
2822 | 0 | if( !i_last_pixel ) |
2823 | 0 | { |
2824 | 0 | bs_write( s, 1, 0 ); |
2825 | 0 | bs_write( s, 7, i_length ); /* pseudo color 0 */ |
2826 | 0 | } |
2827 | 0 | else |
2828 | 0 | { |
2829 | 0 | bs_write( s, 1, 1 ); |
2830 | 0 | bs_write( s, 7, i_length ); |
2831 | 0 | bs_write( s, 8, i_last_pixel ); |
2832 | 0 | } |
2833 | 0 | } |
2834 | |
|
2835 | 0 | if( i == p_region->fmt.i_visible_width ) break; |
2836 | | |
2837 | 0 | i_last_pixel = p_data[i]; |
2838 | 0 | i_length = 1; |
2839 | 0 | } |
2840 | | |
2841 | | /* Stop */ |
2842 | 0 | bs_write( s, 8, 0 ); |
2843 | 0 | bs_write( s, 8, 0 ); |
2844 | | |
2845 | | /* Stuffing */ |
2846 | 0 | bs_align_0( s ); |
2847 | 0 | } |
2848 | | |
2849 | | #endif |
2850 | | |
2851 | | static void default_dds_init( decoder_t * p_dec ) |
2852 | 1.96k | { |
2853 | 1.96k | decoder_sys_t *p_sys = p_dec->p_sys; |
2854 | | |
2855 | | /* see notes on DDS at the top of the file */ |
2856 | | |
2857 | | /* configure for SD res in case DDS is not present */ |
2858 | 1.96k | p_sys->display.i_version = 0xff; /* an invalid version so it's always different */ |
2859 | 1.96k | p_sys->display.i_width_minus1 = 720-1; |
2860 | 1.96k | p_sys->display.i_height_minus1 = 576-1; |
2861 | | p_sys->display.b_windowed = false; |
2862 | 1.96k | } |