qml/KeyNavigableTableView: Add 'delegate' and 'contentY' aliases
[vlc.git] / modules / codec / substx3g.c
blob8315f1e194b7078345b3c6bfa485d871f2f9cdc0
1 /*****************************************************************************
2 * substx3gsub.c : MP4 tx3g subtitles decoder
3 *****************************************************************************
4 * Copyright (C) 2014 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation, Inc.,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_codec.h>
28 #include <vlc_sout.h>
29 #include <vlc_charset.h>
31 #include "substext.h"
32 #include "../demux/mp4/minibox.h"
34 /*****************************************************************************
35 * Module descriptor.
36 *****************************************************************************/
37 static int OpenDecoder ( vlc_object_t * );
38 static void CloseDecoder ( vlc_object_t * );
39 static int Decode( decoder_t *, block_t * );
40 #ifdef ENABLE_SOUT
41 static int OpenEncoder ( vlc_object_t * );
42 static block_t * Encode( encoder_t *, subpicture_t * );
43 #endif
45 vlc_module_begin ()
46 set_description( N_("tx3g subtitles decoder") )
47 set_shortname( N_("tx3g subtitles") )
48 set_capability( "spu decoder", 100 )
49 set_category( CAT_INPUT )
50 set_subcategory( SUBCAT_INPUT_SCODEC )
51 set_callbacks( OpenDecoder, CloseDecoder )
52 #ifdef ENABLE_SOUT
53 add_submodule ()
54 set_description( N_("tx3g subtitles encoder") )
55 set_shortname( N_("tx3g subtitles encoder") )
56 set_capability( "encoder", 101 )
57 set_callback( OpenEncoder )
58 #endif
59 vlc_module_end ()
61 /****************************************************************************
62 * Local structs
63 ****************************************************************************/
65 /*****************************************************************************
66 * Local:
67 *****************************************************************************/
69 #define FONT_FACE_BOLD 0x1
70 #define FONT_FACE_ITALIC 0x2
71 #define FONT_FACE_UNDERLINE 0x4
73 static int ConvertToVLCFlags( int i_atomflags )
75 int i_vlcstyles_flags = 0;
76 if ( i_atomflags & FONT_FACE_BOLD )
77 i_vlcstyles_flags |= STYLE_BOLD;
78 if ( i_atomflags & FONT_FACE_ITALIC )
79 i_vlcstyles_flags |= STYLE_ITALIC;
80 if ( i_atomflags & FONT_FACE_UNDERLINE )
81 i_vlcstyles_flags |= STYLE_UNDERLINE;
82 return i_vlcstyles_flags;
85 static size_t str8len( const char *psz_string )
87 const char *psz_tmp = psz_string;
88 size_t i=0;
89 while ( *psz_tmp )
91 if ( (*psz_tmp & 0xC0) != 0x80 ) i++;
92 psz_tmp++;
94 return i;
97 static char * str8indup( const char *psz_string, size_t i_skip, size_t n )
99 for( size_t i = 0; i< i_skip && *psz_string; i++ )
101 while( *(++psz_string) && (*psz_string & 0xC0) == 0x80 )
105 if ( ! *psz_string )
106 return NULL;
108 const char *psz_tmp = psz_string;
109 for( size_t i = 0; i < n && *psz_tmp; i++ )
111 while( *(++psz_tmp) && (*psz_tmp & 0xC0) == 0x80 )
115 return strndup( psz_string, psz_tmp - psz_string );
118 typedef struct tx3g_segment_t tx3g_segment_t;
120 struct tx3g_segment_t
122 text_segment_t *s;
123 size_t i_size;
124 tx3g_segment_t *p_next3g;
127 static tx3g_segment_t * tx3g_segment_New( const char *psz_string )
129 tx3g_segment_t *p_seg = malloc( sizeof(tx3g_segment_t) );
130 if( p_seg )
132 p_seg->i_size = 0;
133 p_seg->p_next3g = NULL;
134 p_seg->s = text_segment_New( psz_string );
135 if( !p_seg->s )
137 free( p_seg );
138 p_seg = NULL;
141 return p_seg;
144 static void SegmentDoSplit( tx3g_segment_t *p_segment, uint16_t i_start, uint16_t i_end,
145 tx3g_segment_t **pp_segment_left,
146 tx3g_segment_t **pp_segment_middle,
147 tx3g_segment_t **pp_segment_right )
149 tx3g_segment_t *p_segment_left = NULL, *p_segment_right = NULL, *p_segment_middle = NULL;
151 if ( (p_segment->i_size - i_start < 1) || (p_segment->i_size - i_end < 1) )
152 goto error;
154 if ( i_start > 0 )
156 char* psz_text = str8indup( p_segment->s->psz_text, 0, i_start );
157 p_segment_left = tx3g_segment_New( psz_text );
158 free( psz_text );
159 if ( !p_segment_left ) goto error;
160 p_segment_left->s->style = text_style_Duplicate( p_segment->s->style );
161 p_segment_left->i_size = str8len( p_segment_left->s->psz_text );
164 char* psz_midtext = str8indup( p_segment->s->psz_text, i_start, i_end - i_start + 1 );
165 p_segment_middle = tx3g_segment_New( psz_midtext );
166 free( psz_midtext );
167 if ( !p_segment_middle ) goto error;
168 p_segment_middle->s->style = text_style_Duplicate( p_segment->s->style );
169 p_segment_middle->i_size = str8len( p_segment_middle->s->psz_text );
171 if ( i_end < (p_segment->i_size - 1) )
173 char* psz_text = str8indup( p_segment->s->psz_text, i_end + 1, p_segment->i_size - i_end - 1 );
174 p_segment_right = tx3g_segment_New( psz_text );
175 free( psz_text );
176 if ( !p_segment_right ) goto error;
177 p_segment_right->s->style = text_style_Duplicate( p_segment->s->style );
178 p_segment_right->i_size = str8len( p_segment_right->s->psz_text );
181 if ( p_segment_left ) p_segment_left->p_next3g = p_segment_middle;
182 if ( p_segment_right ) p_segment_middle->p_next3g = p_segment_right;
184 *pp_segment_left = p_segment_left;
185 *pp_segment_middle = p_segment_middle;
186 *pp_segment_right = p_segment_right;
188 return;
190 error:
191 if( p_segment_middle )
193 text_segment_Delete( p_segment_middle->s );
194 free( p_segment_middle );
196 if( p_segment_left )
198 text_segment_Delete( p_segment_left->s );
199 free( p_segment_left );
201 *pp_segment_left = *pp_segment_middle = *pp_segment_right = NULL;
204 static bool SegmentSplit( tx3g_segment_t *p_prev, tx3g_segment_t **pp_segment,
205 const uint16_t i_start, const uint16_t i_end,
206 const text_style_t *p_styles )
208 tx3g_segment_t *p_segment_left = NULL, *p_segment_middle = NULL, *p_segment_right = NULL;
210 if ( (*pp_segment)->i_size == 0 ) return false;
211 if ( i_start > i_end ) return false;
212 if ( (size_t)(i_end - i_start) > (*pp_segment)->i_size - 1 ) return false;
213 if ( i_end > (*pp_segment)->i_size - 1 ) return false;
215 SegmentDoSplit( *pp_segment, i_start, i_end, &p_segment_left, &p_segment_middle, &p_segment_right );
216 if ( !p_segment_middle )
218 /* Failed */
219 text_segment_Delete( p_segment_left->s );
220 free( p_segment_left );
221 text_segment_Delete( p_segment_right->s );
222 free( p_segment_right );
223 return false;
226 tx3g_segment_t *p_next3g = (*pp_segment)->p_next3g;
227 text_segment_Delete( (*pp_segment)->s );
228 free( *pp_segment );
229 *pp_segment = ( p_segment_left ) ? p_segment_left : p_segment_middle ;
230 if ( p_prev ) p_prev->p_next3g = *pp_segment;
232 if ( p_segment_right )
233 p_segment_right->p_next3g = p_next3g;
234 else
235 p_segment_middle->p_next3g = p_next3g;
237 if( p_segment_middle->s->style )
238 text_style_Merge( p_segment_middle->s->style, p_styles, true );
239 else
240 p_segment_middle->s->style = text_style_Duplicate( p_styles );
242 return true;
245 /* Creates a new segment using the given style and split existing ones according
246 to the start & end offsets */
247 static void ApplySegmentStyle( tx3g_segment_t **pp_segment, const uint16_t i_absstart,
248 const uint16_t i_absend, const text_style_t *p_styles )
250 /* find the matching segment */
251 uint16_t i_curstart = 0;
252 tx3g_segment_t *p_prev = NULL;
253 tx3g_segment_t *p_cur = *pp_segment;
254 while ( p_cur )
256 uint16_t i_curend = i_curstart + p_cur->i_size - 1;
257 if ( (i_absstart >= i_curstart) && (i_absend <= i_curend) )
259 /* segment found */
260 if ( !SegmentSplit( p_prev, &p_cur, i_absstart - i_curstart,
261 i_absend - i_curstart, p_styles ) )
262 return;
263 if ( !p_prev ) *pp_segment = p_cur;
264 break;
266 else
268 i_curstart += p_cur->i_size;
269 p_prev = p_cur;
270 p_cur = p_cur->p_next3g;
275 /* Do relative size conversion using default style size (from stsd),
276 as the line should always be 5%. Apply to each segment specific text size */
277 static void FontSizeConvert( const text_style_t *p_reference, text_style_t *p_style )
279 if( unlikely(!p_style) )
281 return;
283 else if( unlikely(!p_reference) || p_reference->i_font_size == 0 )
285 p_style->i_font_size = 0;
286 p_style->f_font_relsize = 5.0;
288 else
290 p_style->f_font_relsize = 5.0 * (float) p_style->i_font_size / p_reference->i_font_size;
291 p_style->i_font_size = 0;
295 /*****************************************************************************
296 * Decode:
297 *****************************************************************************/
298 static int Decode( decoder_t *p_dec, block_t *p_block )
300 subpicture_t *p_spu = NULL;
302 if( p_block == NULL ) /* No Drain */
303 return VLCDEC_SUCCESS;
305 if( ( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) ||
306 p_block->i_buffer < sizeof(uint16_t) )
308 block_Release( p_block );
309 return VLCDEC_SUCCESS;
312 uint8_t *p_buf = p_block->p_buffer;
314 /* Read our raw string and create the styled segment for HTML */
315 uint16_t i_psz_bytelength = GetWBE( p_buf );
316 if( p_block->i_buffer < i_psz_bytelength + 2U )
318 block_Release( p_block );
319 return VLCDEC_SUCCESS;
322 const uint8_t *p_pszstart = p_block->p_buffer + sizeof(uint16_t);
323 char *psz_subtitle;
324 if ( i_psz_bytelength > 2 &&
325 ( !memcmp( p_pszstart, "\xFE\xFF", 2 ) || !memcmp( p_pszstart, "\xFF\xFE", 2 ) )
328 psz_subtitle = FromCharset( "UTF-16", p_pszstart, i_psz_bytelength );
329 if ( !psz_subtitle )
330 return VLCDEC_SUCCESS;
332 else
334 psz_subtitle = strndup( (const char*) p_pszstart, i_psz_bytelength );
335 if ( !psz_subtitle )
336 return VLCDEC_SUCCESS;
338 p_buf += i_psz_bytelength + sizeof(uint16_t);
340 for( uint16_t i=0; i < i_psz_bytelength; i++ )
341 if ( psz_subtitle[i] == '\r' ) psz_subtitle[i] = '\n';
343 tx3g_segment_t *p_segment3g = tx3g_segment_New( psz_subtitle );
344 p_segment3g->i_size = str8len( psz_subtitle );
345 free( psz_subtitle );
347 if ( !p_segment3g->s->psz_text )
349 text_segment_Delete( p_segment3g->s );
350 free( p_segment3g );
351 return VLCDEC_SUCCESS;
354 /* Create the subpicture unit */
355 p_spu = decoder_NewSubpictureText( p_dec );
356 if( !p_spu )
358 text_segment_Delete( p_segment3g->s );
359 free( p_segment3g );
360 return VLCDEC_SUCCESS;
363 subtext_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
364 const text_style_t *p_root_style = (text_style_t *) p_dec->p_sys;
366 mp4_box_iterator_t it;
367 mp4_box_iterator_Init( &it, p_buf,
368 p_block->i_buffer - (p_buf - p_block->p_buffer) );
369 /* Parse our styles */
370 if( p_dec->fmt_in.i_codec != VLC_CODEC_QTXT )
371 while( mp4_box_iterator_Next( &it ) )
373 switch( it.i_type )
376 case VLC_FOURCC('s','t','y','l'):
378 if( it.i_payload < 14 )
379 break;
381 uint16_t i_nbrecords = GetWBE(it.p_payload);
382 uint16_t i_cur_record = 0;
384 it.p_payload += 2; it.i_payload -= 2;
385 while( i_cur_record++ < i_nbrecords && it.i_payload >= 12 )
387 uint16_t i_start = __MIN( GetWBE(it.p_payload), i_psz_bytelength - 1 );
388 uint16_t i_end = GetWBE(it.p_payload + 2); /* index is past last char */
389 if( i_start < i_end )
391 i_end = VLC_CLIP( i_end - 1, i_start, i_psz_bytelength - 1 );
393 text_style_t *p_style = text_style_Create( STYLE_NO_DEFAULTS );
394 if( p_style )
396 if( (p_style->i_style_flags = ConvertToVLCFlags( it.p_payload[6] )) )
397 p_style->i_features |= STYLE_HAS_FLAGS;
398 p_style->i_font_size = it.p_payload[7];
399 p_style->i_font_color = GetDWBE(&it.p_payload[8]) >> 8;// RGBA -> RGB
400 p_style->i_font_alpha = GetDWBE(&it.p_payload[8]) & 0xFF;
401 p_style->i_features |= STYLE_HAS_FONT_COLOR | STYLE_HAS_FONT_ALPHA;
402 ApplySegmentStyle( &p_segment3g, i_start, i_end, p_style );
403 text_style_Delete( p_style );
407 it.p_payload += 12; it.i_payload -= 12;
409 } break;
412 default:
413 break;
418 p_spu->i_start = p_block->i_pts;
419 p_spu->i_stop = p_block->i_pts + p_block->i_length;
420 p_spu->b_ephemer = (p_block->i_length == VLC_TICK_INVALID);
421 p_spu->b_absolute = false;
423 p_spu_sys->region.align = SUBPICTURE_ALIGN_BOTTOM;
425 text_style_Merge( p_spu_sys->p_default_style, p_root_style, true );
426 FontSizeConvert( p_root_style, p_spu_sys->p_default_style );
428 /* Unwrap */
429 text_segment_t *p_text_segments = p_segment3g->s;
430 text_segment_t *p_cur = p_text_segments;
431 while( p_segment3g )
433 FontSizeConvert( p_root_style, p_segment3g->s->style );
435 tx3g_segment_t * p_old = p_segment3g;
436 p_segment3g = p_segment3g->p_next3g;
437 free( p_old );
438 if( p_segment3g )
439 p_cur->p_next = p_segment3g->s;
440 p_cur = p_cur->p_next;
443 p_spu_sys->region.p_segments = p_text_segments;
445 block_Release( p_block );
447 decoder_QueueSub( p_dec, p_spu );
448 return VLCDEC_SUCCESS;
451 /*****************************************************************************
452 * Extradata Parsing
453 *****************************************************************************/
454 static void ParseExtradataTx3g( decoder_t *p_dec )
456 text_style_t *p_style = (text_style_t *) p_dec->p_sys;
457 const uint8_t *p_extra = p_dec->fmt_in.p_extra;
459 if( p_dec->fmt_in.i_extra < 32 )
460 return;
462 /* DF @0 */
463 /* Just @4 */
465 /* BGColor @6 */
466 p_style->i_background_color = GetDWBE(&p_extra[6]) >> 8;
467 p_style->i_background_alpha = p_extra[9];
468 p_style->i_features |= STYLE_HAS_BACKGROUND_COLOR|STYLE_HAS_BACKGROUND_ALPHA;
470 /* BoxRecord @10 */
472 /* StyleRecord @18 */
473 p_style->i_style_flags = ConvertToVLCFlags( p_extra[24] );
474 if( p_style->i_style_flags )
475 p_style->i_features |= STYLE_HAS_FLAGS;
476 p_style->i_font_size = p_extra[25];
477 p_style->i_font_color = GetDWBE(&p_extra[26]) >> 8;// RGBA -> RGB
478 p_style->i_font_alpha = p_extra[29];
479 p_style->i_features |= STYLE_HAS_FONT_COLOR | STYLE_HAS_FONT_ALPHA;
481 /* FontTableBox @30 */
484 static void ParseExtradataTextMedia( decoder_t *p_dec )
486 text_style_t *p_style = (text_style_t *) p_dec->p_sys;
487 const uint8_t *p_extra = p_dec->fmt_in.p_extra;
489 if( p_dec->fmt_in.i_extra < 44 )
490 return;
492 /* DF @0 */
493 uint32_t i_flags = GetDWBE(p_extra);
494 if(i_flags & 0x1000) /* drop shadow */
496 p_style->i_style_flags |= STYLE_SHADOW;
497 p_style->i_features |= STYLE_HAS_SHADOW_COLOR|STYLE_HAS_FLAGS|STYLE_HAS_SHADOW_ALPHA;
498 p_style->i_shadow_color = 0xC0C0C0;
499 p_style->i_shadow_alpha = STYLE_ALPHA_OPAQUE;
501 if(i_flags & 0x4000) /* key text*/
503 /*Controls background color. If this flag is set to 1, the text media handler does not display the
504 background color, so that the text overlay background tracks.*/
505 p_style->i_style_flags &= ~STYLE_BACKGROUND;
508 /* Just @4 */
510 /* BGColor @8, read top of 16 bits */
511 p_style->i_background_color = (p_extra[8] << 16) |
512 (p_extra[10] << 8) |
513 p_extra[12];
514 p_style->i_features |= STYLE_HAS_BACKGROUND_COLOR | STYLE_HAS_BACKGROUND_ALPHA;
515 p_style->i_background_alpha = STYLE_ALPHA_OPAQUE;
517 /* BoxRecord @14 */
518 /* Reserved 64 @22 */
519 /* Font # @30 */
521 /* Font Face @32 */
522 p_style->i_style_flags |= ConvertToVLCFlags( GetWBE(&p_extra[32]) );
523 if( p_style->i_style_flags )
524 p_style->i_features |= STYLE_HAS_FLAGS;
525 /* Reserved 8 @34 */
526 /* Reserved 16 @35 */
527 /* FGColor @37 */
528 p_style->i_font_color = (p_extra[37] << 16) |
529 (p_extra[39] << 8) |
530 p_extra[41];
531 p_style->i_features |= STYLE_HAS_FONT_COLOR;
533 /* FontName Pascal (8 + string) @43 */
535 /*****************************************************************************
536 * Decoder entry/exit points
537 *****************************************************************************/
538 static void CloseDecoder( vlc_object_t *p_this )
540 decoder_t *p_dec = (decoder_t *) p_this;
541 text_style_Delete( (text_style_t *) p_dec->p_sys );
544 static int OpenDecoder( vlc_object_t *p_this )
546 decoder_t *p_dec = (decoder_t *) p_this;
548 if( p_dec->fmt_in.i_codec != VLC_CODEC_TX3G &&
549 p_dec->fmt_in.i_codec != VLC_CODEC_QTXT )
550 return VLC_EGENERIC;
552 p_dec->pf_decode = Decode;
554 p_dec->p_sys = text_style_Create( STYLE_NO_DEFAULTS );
555 if( !p_dec->p_sys )
556 return VLC_ENOMEM;
558 text_style_t *p_default_style = p_dec->p_sys;
559 p_default_style->i_style_flags |= STYLE_BACKGROUND;
560 p_default_style->i_features |= STYLE_HAS_FLAGS;
562 if( p_dec->fmt_in.i_codec == VLC_CODEC_TX3G )
563 ParseExtradataTx3g( p_dec );
564 else
565 ParseExtradataTextMedia( p_dec );
567 p_dec->fmt_out.i_codec = VLC_CODEC_TEXT;
569 return VLC_SUCCESS;
572 /*****************************************************************************
573 * Encoder entry/exit
574 *****************************************************************************/
575 #ifdef ENABLE_SOUT
576 static void FillExtradataTx3g( void **pp_extra, int *pi_extra )
578 size_t i_extra = 32 + 37;
579 uint8_t *p_extra = calloc( 1, i_extra );
580 if( p_extra )
582 p_extra[4] = 0x01;/* 1 center, horizontal */
583 p_extra[5] = 0xFF;/* -1 bottom, vertical */
584 SetDWBE( &p_extra[6], 0x000000FFU ); /* bgcolor */
585 p_extra[25] = STYLE_DEFAULT_FONT_SIZE;
586 SetDWBE( &p_extra[26], 0xFFFFFFFFU ); /* fgcolor */
588 /* FontTableBox */
589 SetDWBE(&p_extra[32], 8 + 2 + 6 + 11 + 10);
590 memcpy(&p_extra[36], "ftab", 4);
592 SetWBE(&p_extra[40], 3); /* entry count */
593 /* Font Record 0 */
594 p_extra[41] = 5;
595 memcpy(&p_extra[42], "Serif", 5);
596 /* Font Record 1 */
597 p_extra[47] = 10;
598 memcpy(&p_extra[48], "Sans-serif", 10);
599 /* Font Record 2 */
600 p_extra[58] = 9;
601 memcpy(&p_extra[59], "Monospace", 9);
603 *pp_extra = p_extra;
604 *pi_extra = i_extra;
608 static int OpenEncoder( vlc_object_t *p_this )
610 encoder_t *p_enc = (encoder_t *)p_this;
612 if( p_enc->fmt_out.i_codec != VLC_CODEC_TX3G )
613 return VLC_EGENERIC;
615 p_enc->fmt_in.i_codec = VLC_CODEC_TEXT;
617 p_enc->p_sys = NULL;
619 p_enc->pf_encode_sub = Encode;
620 p_enc->fmt_out.i_cat = SPU_ES;
622 if( !p_enc->fmt_out.i_extra )
623 FillExtradataTx3g( &p_enc->fmt_out.p_extra, &p_enc->fmt_out.i_extra );
625 return VLC_SUCCESS;
628 static int ConvertFromVLCFlags( const text_style_t *p_style )
630 int i_atomflags = 0;
631 if( p_style->i_features & STYLE_HAS_FLAGS )
633 if ( p_style->i_style_flags & STYLE_BOLD )
634 i_atomflags |= FONT_FACE_BOLD;
635 if ( p_style->i_style_flags & STYLE_ITALIC )
636 i_atomflags |= FONT_FACE_ITALIC;
637 if ( p_style->i_style_flags & STYLE_UNDERLINE )
638 i_atomflags |= FONT_FACE_UNDERLINE;
640 return i_atomflags;
643 static uint32_t ConvertFromVLCColor( const text_style_t *p_style )
645 uint32_t rgba = 0;
646 if( p_style->i_features & STYLE_HAS_FONT_COLOR )
647 rgba = ((uint32_t)p_style->i_font_color) << 8;
648 else
649 rgba = 0xFFFFFF00U;
650 if( p_style->i_features & STYLE_HAS_FONT_ALPHA )
651 rgba |= p_style->i_font_alpha;
652 else
653 rgba |= 0xFF;
654 return rgba;
657 static bool NeedStyling( const text_segment_t *p_segment )
659 const text_style_t *p_style = p_segment->style;
660 if( !p_style )
661 return false;
663 if( p_style->i_features & STYLE_HAS_FLAGS )
665 if( p_style->i_style_flags & (STYLE_BOLD|STYLE_ITALIC|STYLE_UNDERLINE) )
666 return true;
669 if( p_style->i_features & (STYLE_HAS_FONT_COLOR|STYLE_HAS_FONT_ALPHA) )
670 return true;
672 return false;
675 static block_t *GetStylBlock( const text_segment_t *p_segment, size_t i_styles )
677 size_t i_start = 0;
678 block_t *p_styl = block_Alloc( 10 + 12 * i_styles );
679 if( p_styl )
681 SetDWBE( p_styl->p_buffer, p_styl->i_buffer );
682 memcpy( &p_styl->p_buffer[4], "styl", 4 );
683 SetWBE( &p_styl->p_buffer[8], i_styles );
684 p_styl->i_buffer = 10;
685 for( ; p_segment; p_segment = p_segment->p_next )
687 size_t i_len = str8len( p_segment->psz_text );
688 if( NeedStyling( p_segment ) )
690 uint8_t *p = &p_styl->p_buffer[p_styl->i_buffer];
691 SetWBE( &p[0], i_start );
692 SetWBE( &p[2], i_start + i_len );
693 SetWBE( &p[4], 0 );
694 p[6] = ConvertFromVLCFlags( p_segment->style );
695 p[7] = STYLE_DEFAULT_FONT_SIZE;
696 SetDWBE(&p[8], ConvertFromVLCColor( p_segment->style ) );
697 p_styl->i_buffer += 12;
699 i_start += i_len;
702 return p_styl;
705 static block_t * Encode( encoder_t *p_enc, subpicture_t *p_spu )
707 VLC_UNUSED(p_enc);
708 const text_segment_t *p_segments = (p_spu->p_region)
709 ? p_spu->p_region->p_text
710 : NULL;
711 size_t i_len = 0;
712 size_t i_styles = 0;
714 for(const text_segment_t *p_segment = p_segments;
715 p_segment; p_segment = p_segment->p_next )
717 if( p_segment->style )
718 i_styles++;
719 i_len += strlen( p_segment->psz_text );
722 block_t *p_block = block_Alloc( i_len + 2 );
723 if( !p_block )
724 return NULL;
726 SetWBE(p_block->p_buffer, i_len);
727 p_block->i_buffer = 2;
728 for(const text_segment_t *p_segment = p_segments;
729 p_segment; p_segment = p_segment->p_next )
731 size_t i_seglen = strlen(p_segment->psz_text);
732 memcpy(&p_block->p_buffer[p_block->i_buffer],
733 p_segment->psz_text, i_seglen);
734 p_block->i_buffer += i_seglen;
736 p_block->i_dts = p_block->i_pts = p_spu->i_start;
737 p_block->i_length = p_spu->i_stop - p_spu->i_start;
739 if( i_styles > 0 )
740 p_block->p_next = GetStylBlock( p_segments, i_styles );
742 return block_ChainGather( p_block );
744 #endif