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 *****************************************************************************/
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_codec.h>
29 #include <vlc_charset.h>
32 #include "../demux/mp4/minibox.h"
34 /*****************************************************************************
36 *****************************************************************************/
37 static int OpenDecoder ( vlc_object_t
* );
38 static void CloseDecoder ( vlc_object_t
* );
39 static int Decode( decoder_t
*, block_t
* );
41 static int OpenEncoder ( vlc_object_t
* );
42 static block_t
* Encode( encoder_t
*, subpicture_t
* );
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
)
54 set_description( N_("tx3g subtitles encoder") )
55 set_shortname( N_("tx3g subtitles encoder") )
56 set_capability( "encoder", 101 )
57 set_callback( OpenEncoder
)
61 /****************************************************************************
63 ****************************************************************************/
65 /*****************************************************************************
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
;
91 if ( (*psz_tmp
& 0xC0) != 0x80 ) 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 )
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
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
) );
133 p_seg
->p_next3g
= NULL
;
134 p_seg
->s
= text_segment_New( psz_string
);
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) )
156 char* psz_text
= str8indup( p_segment
->s
->psz_text
, 0, i_start
);
157 p_segment_left
= tx3g_segment_New( 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
);
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
);
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
;
191 if( p_segment_middle
)
193 text_segment_Delete( p_segment_middle
->s
);
194 free( p_segment_middle
);
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
)
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
);
226 tx3g_segment_t
*p_next3g
= (*pp_segment
)->p_next3g
;
227 text_segment_Delete( (*pp_segment
)->s
);
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
;
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 );
240 p_segment_middle
->s
->style
= text_style_Duplicate( p_styles
);
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
;
256 uint16_t i_curend
= i_curstart
+ p_cur
->i_size
- 1;
257 if ( (i_absstart
>= i_curstart
) && (i_absend
<= i_curend
) )
260 if ( !SegmentSplit( p_prev
, &p_cur
, i_absstart
- i_curstart
,
261 i_absend
- i_curstart
, p_styles
) )
263 if ( !p_prev
) *pp_segment
= p_cur
;
268 i_curstart
+= p_cur
->i_size
;
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
) )
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;
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 /*****************************************************************************
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);
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
);
330 return VLCDEC_SUCCESS
;
334 psz_subtitle
= strndup( (const char*) p_pszstart
, i_psz_bytelength
);
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
);
351 return VLCDEC_SUCCESS
;
354 /* Create the subpicture unit */
355 p_spu
= decoder_NewSubpictureText( p_dec
);
358 text_segment_Delete( p_segment3g
->s
);
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
) )
376 case VLC_FOURCC('s','t','y','l'):
378 if( it
.i_payload
< 14 )
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
);
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;
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
);
429 text_segment_t
*p_text_segments
= p_segment3g
->s
;
430 text_segment_t
*p_cur
= p_text_segments
;
433 FontSizeConvert( p_root_style
, p_segment3g
->s
->style
);
435 tx3g_segment_t
* p_old
= p_segment3g
;
436 p_segment3g
= p_segment3g
->p_next3g
;
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 /*****************************************************************************
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 )
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
;
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 )
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
;
510 /* BGColor @8, read top of 16 bits */
511 p_style
->i_background_color
= (p_extra
[8] << 16) |
514 p_style
->i_features
|= STYLE_HAS_BACKGROUND_COLOR
| STYLE_HAS_BACKGROUND_ALPHA
;
515 p_style
->i_background_alpha
= STYLE_ALPHA_OPAQUE
;
518 /* Reserved 64 @22 */
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
;
526 /* Reserved 16 @35 */
528 p_style
->i_font_color
= (p_extra
[37] << 16) |
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
)
552 p_dec
->pf_decode
= Decode
;
554 p_dec
->p_sys
= text_style_Create( STYLE_NO_DEFAULTS
);
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
);
565 ParseExtradataTextMedia( p_dec
);
567 p_dec
->fmt_out
.i_codec
= VLC_CODEC_TEXT
;
572 /*****************************************************************************
574 *****************************************************************************/
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
);
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 */
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 */
595 memcpy(&p_extra
[42], "Serif", 5);
598 memcpy(&p_extra
[48], "Sans-serif", 10);
601 memcpy(&p_extra
[59], "Monospace", 9);
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
)
615 p_enc
->fmt_in
.i_codec
= VLC_CODEC_TEXT
;
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
);
628 static int ConvertFromVLCFlags( const text_style_t
*p_style
)
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
;
643 static uint32_t ConvertFromVLCColor( const text_style_t
*p_style
)
646 if( p_style
->i_features
& STYLE_HAS_FONT_COLOR
)
647 rgba
= ((uint32_t)p_style
->i_font_color
) << 8;
650 if( p_style
->i_features
& STYLE_HAS_FONT_ALPHA
)
651 rgba
|= p_style
->i_font_alpha
;
657 static bool NeedStyling( const text_segment_t
*p_segment
)
659 const text_style_t
*p_style
= p_segment
->style
;
663 if( p_style
->i_features
& STYLE_HAS_FLAGS
)
665 if( p_style
->i_style_flags
& (STYLE_BOLD
|STYLE_ITALIC
|STYLE_UNDERLINE
) )
669 if( p_style
->i_features
& (STYLE_HAS_FONT_COLOR
|STYLE_HAS_FONT_ALPHA
) )
675 static block_t
*GetStylBlock( const text_segment_t
*p_segment
, size_t i_styles
)
678 block_t
*p_styl
= block_Alloc( 10 + 12 * i_styles
);
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
);
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;
705 static block_t
* Encode( encoder_t
*p_enc
, subpicture_t
*p_spu
)
708 const text_segment_t
*p_segments
= (p_spu
->p_region
)
709 ? p_spu
->p_region
->p_text
714 for(const text_segment_t
*p_segment
= p_segments
;
715 p_segment
; p_segment
= p_segment
->p_next
)
717 if( p_segment
->style
)
719 i_len
+= strlen( p_segment
->psz_text
);
722 block_t
*p_block
= block_Alloc( i_len
+ 2 );
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
;
740 p_block
->p_next
= GetStylBlock( p_segments
, i_styles
);
742 return block_ChainGather( p_block
);