1 /*****************************************************************************
2 * aribsub.c : ARIB subtitles decoder
3 *****************************************************************************
4 * Copyright (C) 2012 Naohiro KORIYAMA
6 * Authors: Naohiro KORIYAMA <nkoriyama@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_plugin.h>
29 #include <vlc_codec.h>
33 #include <aribb24/parser.h>
34 #include <aribb24/decoder.h>
37 //#define DEBUG_ARIBSUB 1
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Open( vlc_object_t
* );
43 static void Close( vlc_object_t
* );
44 static int Decode( decoder_t
*, block_t
* );
46 #define IGNORE_RUBY_TEXT N_("Ignore ruby (furigana)")
47 #define IGNORE_RUBY_LONGTEXT N_("Ignore ruby (furigana) in the subtitle.")
48 #define USE_CORETEXT_TEXT N_("Use Core Text renderer")
49 #define USE_CORETEXT_LONGTEXT N_("Use Core Text renderer in the subtitle.")
52 # define ARIBSUB_CFG_PREFIX "aribsub-"
53 set_description( N_("ARIB subtitles decoder") )
54 set_shortname( N_("ARIB subtitles") )
55 set_capability( "spu decoder", 50 )
56 set_category( CAT_INPUT
)
57 set_subcategory( SUBCAT_INPUT_SCODEC
)
58 set_callbacks( Open
, Close
)
60 add_bool( ARIBSUB_CFG_PREFIX
"ignore-ruby", false, IGNORE_RUBY_TEXT
, IGNORE_RUBY_LONGTEXT
, true )
61 add_bool( ARIBSUB_CFG_PREFIX
"use-coretext", false, USE_CORETEXT_TEXT
, USE_CORETEXT_LONGTEXT
, true )
65 /****************************************************************************
67 ****************************************************************************/
74 bool b_ignore_position_adjustment
;
76 arib_instance_t
*p_arib_instance
;
77 char *psz_arib_base_dir
;
80 /*****************************************************************************
82 *****************************************************************************/
83 static subpicture_t
*render( decoder_t
*, arib_parser_t
*,
84 arib_decoder_t
*, block_t
* );
86 static char* get_arib_base_dir( void );
87 static void messages_callback_handler( void *, const char *psz_message
);
89 /*****************************************************************************
90 * Open: probe the decoder and return score
91 *****************************************************************************
92 * Tries to launch a decoder and return score so that the interface is able
94 *****************************************************************************/
95 static int Open( vlc_object_t
*p_this
)
97 decoder_t
*p_dec
= (decoder_t
*) p_this
;
100 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_ARIB_A
&&
101 p_dec
->fmt_in
.i_codec
!= VLC_CODEC_ARIB_C
)
106 p_sys
= (decoder_sys_t
*) calloc( 1, sizeof(decoder_sys_t
) );
112 p_sys
->p_arib_instance
= arib_instance_new( (void *) p_this
);
113 if ( !p_sys
->p_arib_instance
)
119 p_dec
->p_sys
= p_sys
;
120 p_dec
->pf_decode
= Decode
;
121 p_dec
->fmt_out
.i_codec
= 0;
123 p_sys
->b_a_profile
= ( p_dec
->fmt_in
.i_codec
== VLC_CODEC_ARIB_A
);
125 p_sys
->b_ignore_ruby
=
126 var_InheritBool( p_this
, ARIBSUB_CFG_PREFIX
"ignore-ruby" );
127 p_sys
->b_use_coretext
=
128 var_InheritBool( p_this
, ARIBSUB_CFG_PREFIX
"use-coretext" );
129 p_sys
->b_ignore_position_adjustment
= p_sys
->b_use_coretext
;
130 p_sys
->p_arib_instance
->b_use_private_conv
= p_sys
->b_use_coretext
;
131 p_sys
->p_arib_instance
->b_replace_ellipsis
= p_sys
->b_use_coretext
;
133 char *psz_basedir
= get_arib_base_dir();
134 arib_set_base_path( p_sys
->p_arib_instance
, psz_basedir
);
137 arib_register_messages_callback( p_sys
->p_arib_instance
,
138 messages_callback_handler
);
143 /*****************************************************************************
145 *****************************************************************************/
146 static void Close( vlc_object_t
*p_this
)
148 decoder_t
*p_dec
= (decoder_t
*) p_this
;
149 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
151 arib_instance_destroy( p_sys
->p_arib_instance
);
152 free( p_sys
->psz_arib_base_dir
);
154 var_Destroy( p_this
, ARIBSUB_CFG_PREFIX
"ignore-ruby" );
155 var_Destroy( p_this
, ARIBSUB_CFG_PREFIX
"use-coretext" );
160 /*****************************************************************************
162 *****************************************************************************/
163 static int Decode( decoder_t
*p_dec
, block_t
*p_block
)
165 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
167 if( p_block
== NULL
) /* No Drain */
168 return VLCDEC_SUCCESS
;
170 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
172 block_Release( p_block
);
173 return VLCDEC_SUCCESS
;
176 arib_parser_t
*p_parser
= arib_get_parser( p_sys
->p_arib_instance
);
177 arib_decoder_t
*p_decoder
= arib_get_decoder( p_sys
->p_arib_instance
);
178 if ( p_parser
&& p_decoder
)
180 arib_parse_pes( p_parser
, p_block
->p_buffer
, p_block
->i_buffer
);
181 subpicture_t
*p_spu
= render( p_dec
, p_parser
, p_decoder
, p_block
);
183 decoder_QueueSub( p_dec
, p_spu
);
186 block_Release( p_block
);
187 return VLCDEC_SUCCESS
;
190 /* following functions are local */
192 static void messages_callback_handler( void *p_opaque
, const char *psz_message
)
194 decoder_t
*p_dec
= ( decoder_t
* ) p_opaque
;
195 msg_Dbg( p_dec
, "%s", psz_message
);
198 static char* get_arib_base_dir()
200 char *psz_data_dir
= config_GetUserDir( VLC_USERDATA_DIR
);
201 if( psz_data_dir
== NULL
)
206 char *psz_arib_base_dir
;
207 if( asprintf( &psz_arib_base_dir
, "%s"DIR_SEP
"arib", psz_data_dir
) < 0 )
209 psz_arib_base_dir
= NULL
;
211 free( psz_data_dir
);
213 return psz_arib_base_dir
;
216 static subpicture_t
*render( decoder_t
*p_dec
, arib_parser_t
*p_parser
,
217 arib_decoder_t
*p_arib_decoder
, block_t
*p_block
)
219 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
220 subpicture_t
*p_spu
= NULL
;
221 char *psz_subtitle
= NULL
;
224 const unsigned char *psz_data
= arib_parser_get_data( p_parser
, &i_data_size
);
225 if( !psz_data
|| !i_data_size
)
228 size_t i_subtitle_size
= i_data_size
* 4;
229 psz_subtitle
= (char*) calloc( i_subtitle_size
+ 1, sizeof(*psz_subtitle
) );
230 if( psz_subtitle
== NULL
)
234 if( p_sys
->b_a_profile
)
235 arib_initialize_decoder_a_profile( p_arib_decoder
);
237 arib_initialize_decoder_c_profile( p_arib_decoder
);
239 i_subtitle_size
= arib_decode_buffer( p_arib_decoder
,
245 msg_Dbg( p_dec
, "psz_subtitle [%s]", psz_subtitle
);
246 unsigned const char* start
= psz_data
;
247 unsigned const char* end
= psz_data
+ i_data_size
;
248 char* psz_subtitle_data_hex
= (char*) calloc(
249 i_data_size
* 3 + 1, sizeof(char) );
250 char* psz_subtitle_data_hex_idx
= psz_subtitle_data_hex
;
253 sprintf(psz_subtitle_data_hex_idx
, "%02x ", *start
++);
254 psz_subtitle_data_hex_idx
+= 3;
256 msg_Dbg( p_dec
, "psz_subtitle_data [%s]", psz_subtitle_data_hex
);
257 free( psz_subtitle_data_hex
);
260 p_spu
= decoder_NewSubpictureText( p_dec
);
263 goto decoder_NewSubpictureText_failed
;
266 p_spu
->i_start
= p_block
->i_pts
;
267 p_spu
->i_stop
= p_block
->i_pts
+ VLC_TICK_FROM_US(arib_decoder_get_time( p_arib_decoder
));
268 p_spu
->b_ephemer
= (p_spu
->i_start
== p_spu
->i_stop
);
269 p_spu
->b_absolute
= true;
271 arib_spu_updater_sys_t
*p_spu_sys
= p_spu
->updater
.p_sys
;
273 arib_text_region_t
*p_region
= p_spu_sys
->p_region
=
274 (arib_text_region_t
*) calloc( 1, sizeof(arib_text_region_t
) );
275 if( p_region
== NULL
)
279 for( const arib_buf_region_t
*p_buf_region
= arib_decoder_get_regions( p_arib_decoder
);
280 p_buf_region
; p_buf_region
= p_buf_region
->p_next
)
282 if( p_sys
->b_ignore_ruby
&& p_buf_region
->i_fontheight
== 18 )
287 int i_size
= p_buf_region
->p_end
- p_buf_region
->p_start
;
288 char *psz_text
= (char*) calloc( i_size
+ 1, sizeof(char) );
289 if( psz_text
== NULL
)
293 strncpy(psz_text
, p_buf_region
->p_start
, i_size
);
294 psz_text
[i_size
] = '\0';
296 msg_Dbg( p_dec
, "psz_text [%s]", psz_text
);
299 p_region
->psz_text
= strdup( psz_text
);
301 p_region
->psz_fontname
= NULL
;
302 p_region
->i_font_color
= p_buf_region
->i_foreground_color
;
303 p_region
->i_planewidth
= p_buf_region
->i_planewidth
;
304 p_region
->i_planeheight
= p_buf_region
->i_planeheight
;
305 p_region
->i_fontwidth
= p_buf_region
->i_fontwidth
;
306 p_region
->i_fontheight
= p_buf_region
->i_fontheight
;
307 p_region
->i_verint
= p_buf_region
->i_verint
;
308 p_region
->i_horint
= p_buf_region
->i_horint
;
309 p_region
->i_charleft
= p_buf_region
->i_charleft
;
310 p_region
->i_charbottom
= p_buf_region
->i_charbottom
;
311 p_region
->i_charleft_adj
= 0;
312 p_region
->i_charbottom_adj
= 0;
313 if( !p_sys
->b_ignore_position_adjustment
)
315 p_region
->i_charleft_adj
= p_buf_region
->i_horadj
;
316 p_region
->i_charbottom_adj
= p_buf_region
->i_veradj
;
318 p_region
->p_next
= NULL
;
319 if( p_buf_region
->p_next
!= NULL
)
321 p_region
= p_region
->p_next
=
322 (arib_text_region_t
*) calloc( 1, sizeof(arib_text_region_t
) );
323 if( p_region
== NULL
)
330 decoder_NewSubpictureText_failed
:
332 arib_finalize_decoder( p_arib_decoder
);
333 free( psz_subtitle
);