[vlc-devel] [PATCH 2/3] Added STL demuxer/decoder.
Tomer Barletz
barletz at gmail.com
Fri Jun 3 09:24:43 CEST 2011
From: Laurent Aimar <fenrir at videolan.org>
---
modules/codec/Modules.am | 2 +
modules/codec/stl.c | 175 +++++++++++++++++++++++++++++++++
modules/demux/Modules.am | 2 +
modules/demux/stl.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 421 insertions(+), 0 deletions(-)
create mode 100644 modules/codec/stl.c
create mode 100644 modules/demux/stl.c
diff --git a/modules/codec/Modules.am b/modules/codec/Modules.am
index 8dff8b7..5e35eda 100644
--- a/modules/codec/Modules.am
+++ b/modules/codec/Modules.am
@@ -37,6 +37,7 @@ SOURCES_subsdec = subsdec.c substext.h
SOURCES_subsusf = subsusf.c
SOURCES_t140 = t140.c
SOURCES_crystalhd = crystalhd.c
+SOURCES_stl = stl.c
libvlc_LTLIBRARIES += \
liba52_plugin.la \
@@ -55,4 +56,5 @@ libvlc_LTLIBRARIES += \
libsubsdec_plugin.la \
libsubsusf_plugin.la \
libt140_plugin.la \
+ libstl_plugin.la \
$(NULL)
diff --git a/modules/codec/stl.c b/modules/codec/stl.c
new file mode 100644
index 0000000..5113854
--- /dev/null
+++ b/modules/codec/stl.c
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * stl.c: EBU STL decoder
+ *****************************************************************************
+ * Copyright (C) 2010 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_memory.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+ set_description(N_("EBU STL subtitles decoder"))
+ set_category(CAT_INPUT)
+ set_subcategory(SUBCAT_INPUT_SCODEC)
+ set_capability("decoder", 10)
+ set_callbacks(Open, Close)
+vlc_module_end()
+
+/*****************************************************************************
+ * Local definitions/prototypes
+ *****************************************************************************/
+struct decoder_sys_t {
+ int dummy;
+};
+
+static char *ParseText(uint8_t *data, int size)
+{
+ char *text = strdup("");
+ int text_size = 0;
+
+ for (int i = 0; i < size; i++) {
+ uint8_t code = data[i];
+
+ if (code == 0x8f)
+ break;
+
+ char tmp[16] = "";
+ char *t = tmp;
+ if (code >= 0x20 && code <= 0x7f)
+ snprintf(tmp, sizeof(tmp), "%c", code);
+#if 0
+ else if (code == 0x80)
+ snprintf(tmp, sizeof(tmp), "<i>");
+ else if (code == 0x81)
+ snprintf(tmp, sizeof(tmp), "</i>");
+ else if (code == 0x82)
+ snprintf(tmp, sizeof(tmp), "<u>");
+ else if (code == 0x83)
+ snprintf(tmp, sizeof(tmp), "</u>");
+#endif
+ else if (code == 0x8a)
+ snprintf(tmp, sizeof(tmp), "\n");
+ else {
+ fprintf(stderr, "--> %2.2x\n", code);
+ t = NULL;
+ }
+
+ if (!t)
+ continue;
+ size_t t_size = strlen(t);
+ text = realloc_or_free(text, t_size + text_size + 1);
+ if (!text)
+ continue;
+ memcpy(&text[text_size], t, t_size);
+ text_size += t_size;
+ text[text_size] = '\0';
+ }
+ return text;
+}
+
+static subpicture_t *Decode(decoder_t *dec, block_t **block)
+{
+ if (block == NULL || *block == NULL)
+ return NULL;
+
+ subpicture_t *sub = NULL;
+
+ block_t *b = *block; *block = NULL;
+ if (b->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
+ goto exit;
+ if (b->i_buffer < 128)
+ goto exit;
+
+ int payload_size = (b->i_buffer / 128) * 112;
+ uint8_t *payload = malloc(payload_size);
+ if (!payload)
+ goto exit;
+ for (int i = 0; i < b->i_buffer / 128; i++)
+ memcpy(&payload[112 * i], &b->p_buffer[128 * i + 16], 112);
+
+ sub = decoder_NewSubpicture(dec, NULL);
+ if (!sub) {
+ free(payload);
+ goto exit;
+ }
+ sub->i_start = b->i_pts;
+ sub->i_stop = b->i_pts + b->i_length;
+ sub->b_ephemer = b->i_length == 0;
+ sub->b_absolute = false;
+ //sub->i_original_picture_width = 0;
+ //sub->i_original_picture_height = 0;
+
+ video_format_t fmt;
+ video_format_Init(&fmt, VLC_CODEC_TEXT);
+ sub->p_region = subpicture_region_New(&fmt);
+ video_format_Clean(&fmt);
+
+ if (sub->p_region) {
+ sub->p_region->psz_text = ParseText(payload, payload_size);
+ sub->p_region->psz_html = NULL;
+ }
+
+ free(payload);
+
+exit:
+ block_Release(b);
+ return sub;
+}
+
+static int Open(vlc_object_t *object)
+{
+ decoder_t *dec = (decoder_t*)object;
+
+ if (dec->fmt_in.i_codec != VLC_CODEC_EBU_STL)
+ return VLC_EGENERIC;
+
+ decoder_sys_t *sys = malloc(sizeof(*sys));
+
+ dec->p_sys = sys;
+ dec->pf_decode_sub = Decode;
+ dec->fmt_out.i_cat = SPU_ES;
+ dec->fmt_out.i_codec = 0;
+ return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *object)
+{
+ decoder_t *dec = (decoder_t*)object;
+ decoder_sys_t *sys = dec->p_sys;
+
+ free(sys);
+}
+
diff --git a/modules/demux/Modules.am b/modules/demux/Modules.am
index c17947c..eae4be9 100644
--- a/modules/demux/Modules.am
+++ b/modules/demux/Modules.am
@@ -32,6 +32,7 @@ SOURCES_gme = gme.c dummy.cpp
SOURCES_sid = sid.cpp
SOURCES_dirac = dirac.c
SOURCES_image = image.c
+SOURCES_demux_stl = stl.c
libvlc_LTLIBRARIES += \
libaiff_plugin.la \
@@ -60,6 +61,7 @@ libvlc_LTLIBRARIES += \
libwav_plugin.la \
libxa_plugin.la \
libimage_plugin.la \
+ libdemux_stl_plugin.la \
$(NULL)
libts_plugin_la_SOURCES = ts.c ../mux/mpeg/csa.c dvb-text.h
diff --git a/modules/demux/stl.c b/modules/demux/stl.c
new file mode 100644
index 0000000..3b6c7dd
--- /dev/null
+++ b/modules/demux/stl.c
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * stl.c: EBU STL demuxer
+ *****************************************************************************
+ * Copyright (C) 2010 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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 <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_demux.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+vlc_module_begin()
+ set_description(N_("EBU STL subtitles parser"))
+ set_category(CAT_INPUT)
+ set_subcategory(SUBCAT_INPUT_DEMUX)
+ set_capability("demux", 1)
+ set_callbacks(Open, Close)
+ add_shortcut("stl", "subtitle")
+vlc_module_end()
+
+/*****************************************************************************
+ * Local definitions/prototypes
+ *****************************************************************************/
+typedef struct {
+ mtime_t start;
+ mtime_t stop;
+ int index;
+ int count;
+} stl_entry_t;
+
+struct demux_sys_t {
+ int count;
+ stl_entry_t *index;
+
+ es_out_id_t *es;
+
+ int current;
+ int64_t next_date;
+};
+
+static int ParseInteger(uint8_t *data, int size)
+{
+ char tmp[16];
+ assert(size < sizeof(tmp));
+ memcpy(tmp, data, size);
+ tmp[size] = '\0';
+
+ return strtol(tmp, NULL, 10);
+}
+static int64_t ParseTimeCode(uint8_t *data, double fps)
+{
+ return INT64_C(1000000) * (data[0] * 3600 +
+ data[1] * 60 +
+ data[2] * 1 +
+ data[3] / fps);
+}
+static int64_t ParseTextTimeCode(uint8_t *data, double fps)
+{
+ uint8_t tmp[4];
+ for (int i = 0; i < 4; i++)
+ tmp[i] = ParseInteger(&data[2 * i], 2);
+ return ParseTimeCode(tmp, fps);
+}
+
+static int Control(demux_t *demux, int query, va_list args)
+{
+ demux_sys_t *sys = demux->p_sys;
+ switch(query) {
+ case DEMUX_GET_LENGTH: {
+ int64_t *l = va_arg(args, int64_t *);
+ *l = sys->count > 0 ? sys->index[sys->count-1].stop : 0;
+ return VLC_SUCCESS;
+ }
+ case DEMUX_GET_TIME: {
+ int64_t *t = va_arg(args, int64_t *);
+ *t = sys->current < sys->count ? sys->index[sys->count-1].start : 0;
+ return VLC_SUCCESS;
+ }
+ case DEMUX_SET_NEXT_DEMUX_TIME: {
+ sys->next_date = va_arg(args, int64_t);
+ return VLC_SUCCESS;
+ }
+ case DEMUX_SET_TIME: {
+ int64_t t = va_arg(args, int64_t);
+ sys->current = 0;
+ while (sys->current < sys->count) {
+ if (sys->index[sys->current].stop > t) {
+ stream_Seek(demux->s, 1024 + 128LL * sys->index[sys->current].index);
+ break;
+ }
+ sys->current++;
+ }
+ return VLC_SUCCESS;
+ }
+ case DEMUX_SET_POSITION:
+ case DEMUX_GET_POSITION:
+ default:
+ return VLC_EGENERIC;
+ }
+}
+
+static int Demux(demux_t *demux)
+{
+ demux_sys_t *sys = demux->p_sys;
+
+ while(sys->current < sys->count) {
+ stl_entry_t *s = &sys->index[sys->current];
+ if (s->start > sys->next_date)
+ break;
+
+ block_t *b = stream_Block(demux->s, 128 * s->count);
+ if (b) {
+ b->i_dts =
+ b->i_pts = VLC_TS_0 + s->start;
+ if (s->stop > s->start)
+ b->i_length = s->stop - s->start;
+ es_out_Send(demux->out, sys->es, b);
+ }
+ sys->current++;
+ }
+ return sys->current < sys->count ? 1 : 0;
+}
+
+static int Open(vlc_object_t *object)
+{
+ demux_t *demux = (demux_t*)object;
+
+ const uint8_t *peek;
+ if (stream_Peek(demux->s, &peek, 11) != 11)
+ return VLC_EGENERIC;
+
+ bool is_stl_25 = !memcmp(&peek[3], "STL25.01", 8);
+ bool is_stl_30 = !memcmp(&peek[3], "STL30.01", 8);
+ if (!is_stl_25 && !is_stl_30)
+ return VLC_EGENERIC;
+ const double fps = is_stl_25 ? 25 : 30;
+
+ uint8_t header[1024];
+ if (stream_Read(demux->s, header, sizeof(header)) != sizeof(header)) {
+ msg_Err(demux, "Incomplete EBU STL header");
+ return VLC_EGENERIC;
+ }
+ const int cct = ParseInteger(&header[12], 2);
+ const mtime_t program_start = ParseTextTimeCode(&header[256], fps);
+ const int tti_count = ParseInteger(&header[238], 5);
+ msg_Err(demux, "Detected EBU STL : CCT=%d TTI=%d start=%8.8s %lld", cct, tti_count, &header[256], program_start);
+
+ demux_sys_t *sys = malloc(sizeof(*sys));
+ sys->next_date = 0;
+ sys->current = 0;
+ sys->count = 0;
+ sys->index = calloc(tti_count, sizeof(*sys->index));
+
+
+ bool comment = false;
+ stl_entry_t *s = &sys->index[0];
+ s->count = 0;
+
+ for (int i = 0; i < tti_count; i++) {
+ uint8_t tti[16];
+ if (stream_Read(demux->s, tti, 16) != 16 ||
+ stream_Read(demux->s, NULL, 112) != 112) {
+ msg_Warn(demux, "Incomplete EBU STL file");
+ break;
+ }
+ const int ebn = tti[3];
+ if (ebn >= 0xf0 && ebn <= 0xfd)
+ continue;
+ if (ebn == 0xfe)
+ continue;
+
+ if (s->count <= 0) {
+ comment = tti[15] != 0;
+ s->start = ParseTimeCode(&tti[5], fps) - program_start;
+ s->stop = ParseTimeCode(&tti[9], fps) - program_start;
+ s->index = i;
+ }
+ s->count++;
+ if (ebn == 0xff && !comment)
+ s = &sys->index[++sys->count];
+ if (ebn == 0xff && sys->count < tti_count)
+ s->count = 0;
+ }
+ if (sys->count > 0)
+ stream_Seek(demux->s, 1024 + 128LL * sys->index[0].index);
+
+ es_format_t fmt;
+ es_format_Init(&fmt, SPU_ES, VLC_CODEC_EBU_STL);
+ fmt.i_extra = sizeof(header);
+ fmt.p_extra = header;
+
+ sys->es = es_out_Add(demux->out, &fmt);
+
+ fmt.i_extra = NULL;
+ fmt.p_extra = NULL;
+ es_format_Clean(&fmt);
+
+ demux->p_sys = sys;
+ demux->pf_demux = Demux;
+ demux->pf_control = Control;
+ return VLC_SUCCESS;
+}
+
+static void Close(vlc_object_t *object)
+{
+ demux_t *demux = (demux_t*)object;
+ demux_sys_t *sys = demux->p_sys;
+
+ free(sys->index);
+ free(sys);
+}
+
--
1.7.4.1
More information about the vlc-devel
mailing list