mirror of https://code.videolan.org/videolan/vlc
decoders: add HDMV text subtitles decoder
This commit is contained in:
parent
f95f6c0752
commit
7672393eee
1
NEWS
1
NEWS
|
@ -90,6 +90,7 @@ Decoder:
|
|||
* JPEG images correctly oriented using embedded orientation tag, if present
|
||||
* Support VPX high bit depth support
|
||||
* Extend MicroDVD support with color, fontname, size, position extensions
|
||||
* BluRay text subtitles are now decoded
|
||||
|
||||
Demuxers:
|
||||
* Support HD-DVD .evo (H.264, VC-1, MPEG-2, PCM, AC-3, E-AC3, MLP, DTS)
|
||||
|
|
|
@ -397,6 +397,7 @@ $Id$
|
|||
* tcp: TCP Network access module
|
||||
* tdummy: dummy text renderer
|
||||
* telx: teletext subtitles decoder
|
||||
* textst: HDMV text subtitles decoder
|
||||
* theora: a theora video decoder/packetizer/encoder using the libtheora
|
||||
* timecode: clock/timecode as a subtitle input
|
||||
* tizen_audio: audio output for Tizen
|
||||
|
|
|
@ -233,6 +233,10 @@ libtelx_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
|
|||
EXTRA_LTLIBRARIES += libtelx_plugin.la
|
||||
codec_LTLIBRARIES += $(LTLIBtelx)
|
||||
|
||||
libtextst_plugin_la_SOURCES = codec/textst.c
|
||||
libtextst_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
|
||||
codec_LTLIBRARIES += libtextst_plugin.la
|
||||
|
||||
libzvbi_plugin_la_SOURCES = codec/zvbi.c
|
||||
libzvbi_plugin_la_CFLAGS = $(AM_CFLAGS) $(ZVBI_CFLAGS) $(CFLAGS_zvbi)
|
||||
libzvbi_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
/*****************************************************************************
|
||||
* textst.c: HDMV TextST subtitles decoder
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2017 Videolan Authors
|
||||
*
|
||||
* Adapted from libluray textst_decode.c
|
||||
* Copyright (C) 2013 Petri Hintukainen <phintuka@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Preamble
|
||||
*****************************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <vlc_common.h>
|
||||
#include <vlc_plugin.h>
|
||||
#include <vlc_codec.h>
|
||||
|
||||
#include "substext.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Module descriptor
|
||||
*****************************************************************************/
|
||||
static int Open (vlc_object_t *);
|
||||
static void Close(vlc_object_t *);
|
||||
|
||||
struct decoder_sys_t
|
||||
{
|
||||
uint32_t palette[256];
|
||||
};
|
||||
|
||||
vlc_module_begin()
|
||||
set_description(N_("HDMV TextST subtitles decoder"))
|
||||
set_category(CAT_INPUT)
|
||||
set_subcategory(SUBCAT_INPUT_SCODEC)
|
||||
set_capability("decoder", 10)
|
||||
set_callbacks(Open, Close)
|
||||
vlc_module_end()
|
||||
|
||||
#define BD_TEXTST_DATA_STRING 1
|
||||
#define BD_TEXTST_DATA_FONT_ID 2
|
||||
#define BD_TEXTST_DATA_FONT_STYLE 3
|
||||
#define BD_TEXTST_DATA_FONT_SIZE 4
|
||||
#define BD_TEXTST_DATA_FONT_COLOR 5
|
||||
#define BD_TEXTST_DATA_NEWLINE 0x0a
|
||||
#define BD_TEXTST_DATA_RESET_STYLE 0x0b
|
||||
|
||||
static size_t textst_FillRegion(decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
|
||||
subpicture_updater_sys_region_t *p_region)
|
||||
{
|
||||
VLC_UNUSED(p_dec);
|
||||
text_segment_t **pp_last = &p_region->p_segments;
|
||||
text_style_t *p_style = NULL;
|
||||
|
||||
/* p_data[0] */
|
||||
/* continous_present_flag b1 */
|
||||
/* forced_on_flag b1 */
|
||||
/* ? b6 */
|
||||
|
||||
//uint8_t region_style_id_ref = p_data[1];
|
||||
uint16_t i_data_length = GetWBE(&p_data[2]);
|
||||
|
||||
p_data += 4; i_data -= 4;
|
||||
if( i_data < i_data_length )
|
||||
return i_data;
|
||||
else
|
||||
i_data = i_data_length;
|
||||
|
||||
while (i_data > 3)
|
||||
{
|
||||
/* parse header */
|
||||
uint8_t code = p_data[0];
|
||||
if (code != 0x1b) {
|
||||
p_data++; i_data--;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t type = p_data[1];
|
||||
uint8_t length = p_data[2];
|
||||
|
||||
p_data += 3; i_data -= 3;
|
||||
|
||||
if(length > i_data)
|
||||
break;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case BD_TEXTST_DATA_STRING:
|
||||
{
|
||||
char *psz = strndup((char *)p_data, length);
|
||||
*pp_last = text_segment_New(psz);
|
||||
free(psz);
|
||||
if(p_style && *pp_last)
|
||||
(*pp_last)->style = text_style_Duplicate(p_style);
|
||||
}
|
||||
break;
|
||||
case BD_TEXTST_DATA_FONT_ID:
|
||||
//p_data[0] font_id;
|
||||
break;
|
||||
case BD_TEXTST_DATA_FONT_STYLE:
|
||||
if(p_style || (p_style = text_style_Create( STYLE_NO_DEFAULTS )))
|
||||
{
|
||||
if(p_data[0] & 0x01)
|
||||
p_style->i_style_flags |= STYLE_BOLD;
|
||||
if(p_data[0] & 0x02)
|
||||
p_style->i_style_flags |= STYLE_ITALIC;
|
||||
if(p_data[0] & 0x04)
|
||||
p_style->i_style_flags |= STYLE_OUTLINE;
|
||||
p_style->i_outline_color = p_dec->p_sys->palette[p_data[1]] & 0x00FFFFFF;
|
||||
p_style->i_outline_alpha = p_dec->p_sys->palette[p_data[1]] >> 24;
|
||||
p_style->i_features |= STYLE_HAS_FLAGS | STYLE_HAS_OUTLINE_ALPHA | STYLE_HAS_OUTLINE_COLOR;
|
||||
//p_data[2] outline__thickness
|
||||
}
|
||||
break;
|
||||
case BD_TEXTST_DATA_FONT_SIZE:
|
||||
/*p_style->f_font_relsize = STYLE_DEFAULT_REL_FONT_SIZE *
|
||||
(p_data[0] << 4) / STYLE_DEFAULT_FONT_SIZE;*/
|
||||
break;
|
||||
case BD_TEXTST_DATA_FONT_COLOR:
|
||||
p_style->i_font_color = p_dec->p_sys->palette[p_data[1]] & 0x00FFFFFF;
|
||||
p_style->i_font_alpha = p_dec->p_sys->palette[p_data[1]] >> 24;
|
||||
p_style->i_features |= STYLE_HAS_FONT_ALPHA | STYLE_HAS_FONT_COLOR;
|
||||
break;
|
||||
case BD_TEXTST_DATA_NEWLINE:
|
||||
*pp_last = text_segment_New("\n");
|
||||
break;
|
||||
case BD_TEXTST_DATA_RESET_STYLE:
|
||||
if(p_style)
|
||||
{
|
||||
text_style_Delete(p_style);
|
||||
p_style = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(*pp_last)
|
||||
pp_last = &(*pp_last)->p_next;
|
||||
|
||||
p_data += length; i_data -= length;
|
||||
}
|
||||
|
||||
if(p_style)
|
||||
text_style_Delete(p_style);
|
||||
|
||||
return i_data_length;
|
||||
}
|
||||
|
||||
static size_t textst_Decode_palette(decoder_t *p_dec, const uint8_t *p_data, size_t i_data)
|
||||
{
|
||||
uint16_t i_size = GetWBE(&p_data[0]);
|
||||
i_size = i_data = __MIN(i_data, i_size);
|
||||
if(i_data > 0)
|
||||
{
|
||||
p_data++; i_data--;
|
||||
while (i_data > 4)
|
||||
{
|
||||
p_dec->p_sys->palette[p_data[0]] = /* YCrCbT to ARGB */
|
||||
( (uint32_t)((float)p_data[1] +1.402f * (p_data[2]-128)) << 16 ) |
|
||||
( (uint32_t)((float)p_data[1] -0.34414 * (p_data[3]-128) -0.71414 * (p_data[2]-128)) << 8 ) |
|
||||
( (uint32_t)((float)p_data[1] +1.722 * (p_data[3]-128)) ) |
|
||||
( (0xFF - p_data[4]) << 24 );
|
||||
p_data += 5; i_data -= 5;
|
||||
}
|
||||
}
|
||||
return i_size;
|
||||
}
|
||||
|
||||
static void textst_FillRegions(decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
|
||||
subpicture_updater_sys_region_t *p_region)
|
||||
{
|
||||
subpicture_updater_sys_region_t **pp_last = &p_region;
|
||||
bool palette_update_flag = p_data[0] >> 7;
|
||||
p_data++; i_data--;
|
||||
|
||||
if (palette_update_flag)
|
||||
{
|
||||
size_t i_read = textst_Decode_palette(p_dec, p_data, i_data);
|
||||
p_data += i_read; i_data -= i_read;
|
||||
}
|
||||
|
||||
if(i_data > 2)
|
||||
{
|
||||
uint8_t i_region_count = p_data[0];
|
||||
p_data++; i_data--;
|
||||
|
||||
for(uint8_t i=0; i<i_region_count && i_data > 0; i++)
|
||||
{
|
||||
if(*pp_last == NULL)
|
||||
{
|
||||
*pp_last = SubpictureUpdaterSysRegionNew();
|
||||
if(!*pp_last)
|
||||
break;
|
||||
}
|
||||
size_t i_read = textst_FillRegion(p_dec, p_data, i_data, *pp_last);
|
||||
(*pp_last)->align = SUBPICTURE_ALIGN_BOTTOM;
|
||||
pp_last = &(*pp_last)->p_next;
|
||||
p_data += i_read; i_data -= i_read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static subpicture_t *Decode(decoder_t *p_dec, block_t **pp_block)
|
||||
{
|
||||
subpicture_t *p_sub = NULL;
|
||||
if (pp_block == NULL || *pp_block == NULL)
|
||||
return NULL;
|
||||
|
||||
block_t *p_block = *pp_block;
|
||||
*pp_block = NULL;
|
||||
|
||||
if(p_block)
|
||||
{
|
||||
if(p_block->i_buffer > 18 &&
|
||||
(p_block->i_flags & BLOCK_FLAG_CORRUPTED) == 0 &&
|
||||
(p_sub = decoder_NewSubpictureText(p_dec)))
|
||||
{
|
||||
p_sub->i_start = ((int64_t) (p_block->p_buffer[3] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[4]);
|
||||
p_sub->i_stop = ((int64_t) (p_block->p_buffer[8] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[9]);
|
||||
p_sub->i_start = VLC_TS_0 + p_sub->i_start * 100 / 9;
|
||||
p_sub->i_stop = VLC_TS_0 + p_sub->i_stop * 100 / 9;
|
||||
if(p_sub->i_start < p_block->i_dts)
|
||||
{
|
||||
p_sub->i_stop += p_block->i_dts - p_sub->i_start;
|
||||
p_sub->i_start = p_block->i_dts;
|
||||
}
|
||||
|
||||
textst_FillRegions(p_dec, &p_block->p_buffer[13], p_block->i_buffer - 13,
|
||||
&p_sub->updater.p_sys->region);
|
||||
|
||||
p_sub->b_absolute = false;
|
||||
}
|
||||
|
||||
block_Release(p_block);
|
||||
}
|
||||
|
||||
return p_sub;
|
||||
}
|
||||
|
||||
static void Close(vlc_object_t *object)
|
||||
{
|
||||
decoder_t *p_dec = (decoder_t*)object;
|
||||
free(p_dec->p_sys);
|
||||
}
|
||||
|
||||
static int Open(vlc_object_t *object)
|
||||
{
|
||||
decoder_t *p_dec = (decoder_t*)object;
|
||||
|
||||
if (p_dec->fmt_in.i_codec != VLC_CODEC_BD_TEXT)
|
||||
return VLC_EGENERIC;
|
||||
|
||||
decoder_sys_t *p_sys = malloc(sizeof(decoder_sys_t));
|
||||
if(!p_sys)
|
||||
return VLC_ENOMEM;
|
||||
memset(p_sys->palette, 0xFF, 256 * sizeof(uint32_t));
|
||||
|
||||
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;
|
||||
|
||||
return VLC_SUCCESS;
|
||||
}
|
||||
|
Loading…
Reference in New Issue