[vlc-commits] decoders: add HDMV text subtitles decoder
Francois Cartegnie
git at videolan.org
Mon Jan 30 17:42:15 CET 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Jan 30 13:25:17 2017 +0100| [7672393eee5539d0815e80329c7abea14f4ed480] | committer: Francois Cartegnie
decoders: add HDMV text subtitles decoder
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=7672393eee5539d0815e80329c7abea14f4ed480
---
NEWS | 1 +
modules/MODULES_LIST | 1 +
modules/codec/Makefile.am | 4 +
modules/codec/textst.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 288 insertions(+)
diff --git a/NEWS b/NEWS
index 8c684c6..c589109 100644
--- a/NEWS
+++ b/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)
diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
index 02ea857..42e83d0 100644
--- a/modules/MODULES_LIST
+++ b/modules/MODULES_LIST
@@ -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
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 2154906..b201be4 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -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)'
diff --git a/modules/codec/textst.c b/modules/codec/textst.c
new file mode 100644
index 0000000..795d3b2
--- /dev/null
+++ b/modules/codec/textst.c
@@ -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 at 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;
+}
+
More information about the vlc-commits
mailing list