[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