Skip to content

Commit

Permalink
codecs: add support for ARIB subtitles
Browse files Browse the repository at this point in the history
Fixed-by: Francois Cartegnie <[email protected]>
Signed-off-by: Francois Cartegnie <[email protected]>
  • Loading branch information
nkoriyama authored and fcartegnie committed Aug 15, 2014
1 parent b48567c commit 97c02be
Show file tree
Hide file tree
Showing 9 changed files with 525 additions and 0 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Access:
Decoder:
* OMX GPU-zerocopy support for decoding and display on Android using OpenMax IL
* Support 4:4:4 chroma sampling with VDPAU hw acceleration
* Support for ARIB B24 subtitles

Demuxers:
* Support HD-DVD .evo (H.264, VC-1, MPEG-2, PCM, AC-3, E-AC3, MLP, DTS)
Expand Down
18 changes: 18 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3032,6 +3032,24 @@ AS_IF( [test "${enable_libass}" != "no"], [
])
])

dnl
dnl ARIB subtitles rendering module
dnl
AC_ARG_ENABLE(aribsub,
[ --enable-aribsub ARIB Subtitles support (default enabled)])
AS_IF( [test "${enable_aribsub}" != "no" ],[
PKG_CHECK_MODULES(ARIBB24, [aribb24 >= 1.0.1], [
have_aribb24="yes"
VLC_ADD_PLUGIN([aribsub])
VLC_ADD_LIBS([aribsub],[-laribb24])
AC_DEFINE(HAVE_ARIBB24, 1, [Define if libaribb24 is available.])
],[
AC_MSG_WARN(Library [aribb24] needed for [aribsub] was not found)
have_aribb24="no"
])
AM_CONDITIONAL([HAVE_ARIBB24], [test "${have_aribb24}" = "yes"])
])

dnl
dnl kate decoder plugin
dnl
Expand Down
2 changes: 2 additions & 0 deletions include/vlc_fourcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@
#define VLC_CODEC_OGT VLC_FOURCC('o','g','t',' ')
#define VLC_CODEC_CVD VLC_FOURCC('c','v','d',' ')
#define VLC_CODEC_TX3G VLC_FOURCC('t','x','3','g')
#define VLC_CODEC_ARIB_A VLC_FOURCC('a','r','b','a')
#define VLC_CODEC_ARIB_C VLC_FOURCC('a','r','b','c')
/* Blu-ray Presentation Graphics */
#define VLC_CODEC_BD_PG VLC_FOURCC('b','d','p','g')
/* EBU STL (TECH. 3264-E) */
Expand Down
1 change: 1 addition & 0 deletions modules/MODULES_LIST
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ $Id$
* android_surface: video output for Android, based on Surface
* antiflicker: anti-flicker video filter
* araw: Pseudo audio decoder for raw PCM
* aribsub: ARIB subtitles decoder
* asf: ASF demuxer
* atmo: Ambilight-like video-output
* attachment: Attachment access module
Expand Down
5 changes: 5 additions & 0 deletions modules/codec/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ codec_LTLIBRARIES += libcvdsub_plugin.la
libdvbsub_plugin_la_SOURCES = codec/dvbsub.c
codec_LTLIBRARIES += libdvbsub_plugin.la

libaribsub_plugin_la_SOURCES = codec/arib/aribsub.c codec/arib/substext.h
libaribsub_plugin_la_CFLAGS = $(ARIBB24_CFLAGS)
libaribsub_plugin_la_LIBADD = $(ARIBB24_LIBS)
codec_LTLIBRARIES += libaribsub_plugin.la

libscte27_plugin_la_SOURCES = codec/scte27.c
codec_LTLIBRARIES += libscte27_plugin.la

Expand Down
337 changes: 337 additions & 0 deletions modules/codec/arib/aribsub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
/*****************************************************************************
* aribsub.c : ARIB subtitles decoder
*****************************************************************************
* Copyright (C) 2012 Naohiro KORIYAMA
*
* Authors: Naohiro KORIYAMA <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>

#ifdef HAVE_ARIBB24
#include "substext.h"
#include <aribb24/parser.h>
#include <aribb24/decoder.h>
#endif

//#define DEBUG_ARIBSUB 1

/*****************************************************************************
* Module descriptor.
*****************************************************************************/
static int Open( vlc_object_t * );
static void Close( vlc_object_t * );
static subpicture_t *Decode( decoder_t *, block_t ** );

#define IGNORE_RUBY_TEXT N_("Ignore ruby(furigana)")
#define IGNORE_RUBY_LONGTEXT N_("Ignore ruby(furigana) in the subtitle.")
#define USE_CORETEXT_TEXT N_("Use Core Text renderer")
#define USE_CORETEXT_LONGTEXT N_("Use Core Text renderer in the subtitle.")

vlc_module_begin ()
# define ARIBSUB_CFG_PREFIX "aribsub-"
set_description( N_("ARIB subtitles decoder") )
set_shortname( N_("ARIB subtitles") )
set_capability( "decoder", 50 )
set_category( CAT_INPUT )
set_subcategory( SUBCAT_INPUT_SCODEC )
set_callbacks( Open, Close )

add_bool( ARIBSUB_CFG_PREFIX "ignore-ruby", false, IGNORE_RUBY_TEXT, IGNORE_RUBY_LONGTEXT, true )
add_bool( ARIBSUB_CFG_PREFIX "use-coretext", false, USE_CORETEXT_TEXT, USE_CORETEXT_LONGTEXT, true )
vlc_module_end ()


/****************************************************************************
* Local structures
****************************************************************************/

struct decoder_sys_t
{
bool b_a_profile;
bool b_ignore_ruby;
bool b_use_coretext;
bool b_ignore_position_adjustment;

arib_instance_t *p_arib_instance;
char *psz_arib_base_dir;
};

/*****************************************************************************
* Local prototypes
*****************************************************************************/
static subpicture_t *render( decoder_t *, arib_parser_t *,
arib_decoder_t *, block_t * );

static char* get_arib_base_dir( void );
static void messages_callback_handler( void *, const char *psz_message );

/*****************************************************************************
* Open: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to choose.
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t *) p_this;
decoder_sys_t *p_sys;

if( p_dec->fmt_in.i_codec != VLC_CODEC_ARIB_A &&
p_dec->fmt_in.i_codec != VLC_CODEC_ARIB_C )
{
return VLC_EGENERIC;
}

p_sys = (decoder_sys_t*) calloc( 1, sizeof(decoder_sys_t) );
if( p_sys == NULL )
{
return VLC_ENOMEM;
}

p_sys->p_arib_instance = arib_instance_new( (void *) p_this );
if ( !p_sys->p_arib_instance )
{
free( p_sys );
return VLC_EGENERIC;
}

p_dec->p_sys = p_sys;
p_dec->pf_decode_sub = Decode;
p_dec->fmt_out.i_cat = SPU_ES;
p_dec->fmt_out.i_codec = 0;

p_sys->b_a_profile = ( p_dec->fmt_in.i_codec == VLC_CODEC_ARIB_A );

p_sys->b_ignore_ruby =
var_InheritBool( p_this, ARIBSUB_CFG_PREFIX "ignore-ruby" );
p_sys->b_use_coretext =
var_InheritBool( p_this, ARIBSUB_CFG_PREFIX "use-coretext" );
p_sys->b_ignore_position_adjustment = p_sys->b_use_coretext;
p_sys->p_arib_instance->b_use_private_conv = p_sys->b_use_coretext;
p_sys->p_arib_instance->b_replace_ellipsis = p_sys->b_use_coretext;

char *psz_basedir = get_arib_base_dir();
arib_set_base_path( p_sys->p_arib_instance, psz_basedir );
free( psz_basedir );

arib_register_messages_callback( p_sys->p_arib_instance,
messages_callback_handler );

return VLC_SUCCESS;
}

/*****************************************************************************
* Close:
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*) p_this;
decoder_sys_t *p_sys = p_dec->p_sys;

arib_instance_destroy( p_sys->p_arib_instance );
free( p_sys->psz_arib_base_dir );

var_Destroy( p_this, ARIBSUB_CFG_PREFIX "ignore-ruby" );
var_Destroy( p_this, ARIBSUB_CFG_PREFIX "use-coretext" );

free( p_sys );
}

/*****************************************************************************
* Decode:
*****************************************************************************/
static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_block;
subpicture_t *p_spu = NULL;

if( ( pp_block == NULL ) || ( *pp_block == NULL ) )
{
return NULL;
}
p_block = *pp_block;

arib_parser_t *p_parser = arib_get_parser( p_sys->p_arib_instance );
arib_decoder_t *p_decoder = arib_get_decoder( p_sys->p_arib_instance );
if ( p_parser && p_decoder )
{
arib_parse_pes( p_parser, p_block->p_buffer, p_block->i_buffer );
p_spu = render( p_dec, p_parser, p_decoder, p_block );
}

block_Release( p_block );
*pp_block = NULL;

return p_spu;
}

/* following functions are local */

static void messages_callback_handler( void *p_opaque, const char *psz_message )
{
decoder_t *p_dec = ( decoder_t * ) p_opaque;
msg_Dbg( p_dec, "%s", psz_message );
}

static char* get_arib_base_dir()
{
char *psz_data_dir = config_GetUserDir( VLC_DATA_DIR );
if( psz_data_dir == NULL )
{
return NULL;
}

char *psz_arib_base_dir;
if( asprintf( &psz_arib_base_dir, "%s"DIR_SEP"arib", psz_data_dir ) < 0 )
{
psz_arib_base_dir = NULL;
}
free( psz_data_dir );

return psz_arib_base_dir;
}

static subpicture_t *render( decoder_t *p_dec, arib_parser_t *p_parser,
arib_decoder_t *p_arib_decoder, block_t *p_block )
{
decoder_sys_t *p_sys = p_dec->p_sys;
subpicture_t *p_spu = NULL;
char *psz_subtitle = NULL;

size_t i_data_size;
const unsigned char *psz_data = arib_parser_get_data( p_parser, &i_data_size );
if( !psz_data || !i_data_size )
return NULL;

size_t i_subtitle_size = i_data_size * 4;
psz_subtitle = (char*) calloc( i_subtitle_size + 1, sizeof(*psz_subtitle) );
if( psz_subtitle == NULL )
{
return NULL;
}
if( p_sys->b_a_profile )
arib_initialize_decoder_a_profile( p_arib_decoder );
else
arib_initialize_decoder_c_profile( p_arib_decoder );

i_subtitle_size = arib_decode_buffer( p_arib_decoder,
psz_data,
i_data_size,
psz_subtitle,
i_subtitle_size );
#ifdef DEBUG_ARIBSUB
msg_Dbg( p_dec, "psz_subtitle [%s]", psz_subtitle );
unsigned const char* start = psz_data;
unsigned const char* end = psz_data + i_data_size;
char* psz_subtitle_data_hex = (char*) calloc(
i_data_size * 3 + 1, sizeof(char) );
char* psz_subtitle_data_hex_idx = psz_subtitle_data_hex;
while( start < end )
{
sprintf(psz_subtitle_data_hex_idx, "%02x ", *start++);
psz_subtitle_data_hex_idx += 3;
}
msg_Dbg( p_dec, "psz_subtitle_data [%s]", psz_subtitle_data_hex);
free( psz_subtitle_data_hex );
#endif

p_spu = decoder_NewSubpictureText( p_dec );
if( p_spu == NULL )
{
goto decoder_NewSubpictureText_failed;
}

p_spu->i_start = p_block->i_pts;
p_spu->i_stop = p_block->i_pts + arib_decoder_get_time( p_arib_decoder );
p_spu->b_ephemer = (p_spu->i_start == p_spu->i_stop);
p_spu->b_absolute = true;

subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;

arib_text_region_t *p_region = p_spu_sys->p_region =
(arib_text_region_t*) calloc( 1, sizeof(arib_text_region_t) );
if( p_region == NULL )
{
goto malloc_failed;
}
for( const arib_buf_region_t *p_buf_region = arib_decoder_get_regions( p_arib_decoder );
p_buf_region; p_buf_region = p_buf_region->p_next )
{
if( p_sys->b_ignore_ruby && p_buf_region->i_fontheight == 18 )
{
continue;
}

int i_size = p_buf_region->p_end - p_buf_region->p_start;
char *psz_text = (char*) calloc( i_size + 1, sizeof(char) );
if( psz_text == NULL )
{
goto malloc_failed;
}
strncpy(psz_text, p_buf_region->p_start, i_size);
psz_text[i_size] = '\0';
#ifdef DEBUG_ARIBSUB
msg_Dbg( p_dec, "psz_text [%s]", psz_text );
#endif

p_region->psz_text = strdup( psz_text );
free( psz_text );
p_region->psz_html = NULL;
p_region->psz_fontname = NULL;
p_region->i_font_color = p_buf_region->i_foreground_color;
p_region->i_planewidth = p_buf_region->i_planewidth;
p_region->i_planeheight = p_buf_region->i_planeheight;
p_region->i_fontwidth = p_buf_region->i_fontwidth;
p_region->i_fontheight = p_buf_region->i_fontheight;
p_region->i_verint = p_buf_region->i_verint;
p_region->i_horint = p_buf_region->i_horint;
p_region->i_charleft = p_buf_region->i_charleft;
p_region->i_charbottom = p_buf_region->i_charbottom;
p_region->i_charleft_adj = 0;
p_region->i_charbottom_adj = 0;
if( !p_sys->b_ignore_position_adjustment )
{
p_region->i_charleft_adj = p_buf_region->i_horadj;
p_region->i_charbottom_adj = p_buf_region->i_veradj;
}
p_region->p_next = NULL;
if( p_buf_region->p_next != NULL )
{
p_region = p_region->p_next =
(arib_text_region_t*) calloc( 1, sizeof(arib_text_region_t) );
if( p_region == NULL )
{
goto malloc_failed;
}
}
}

decoder_NewSubpictureText_failed:
malloc_failed:
arib_finalize_decoder( p_arib_decoder );
free( psz_subtitle );

return p_spu;
}
Loading

0 comments on commit 97c02be

Please sign in to comment.