[vlc-devel] [PATCH] Add an access-demux which can retrieve raw subtitles

Denis Charmet typx at dinauz.org
Mon Mar 22 16:30:56 CET 2010


Hello,

I'd like to propose a new acces-demux which can retrieve and send to
the decoder raw subtitles from socket/file/file-descriptor. It has to be
used as input-slave=rawtext:// with option
rawtext-src={tcp,udp,file,fd}://host(:port).

Regards.

-- 
TypX
Le mauvais esprit est un art de vivre

---
 modules/demux/rawtext.c |  449 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 449 insertions(+), 0 deletions(-)
 create mode 100644 modules/demux/rawtext.c

diff --git a/modules/demux/rawtext.c b/modules/demux/rawtext.c
new file mode 100644
index 0000000..65aa86e
--- /dev/null
+++ b/modules/demux/rawtext.c
@@ -0,0 +1,449 @@
+/*****************************************************************************
+ * rawtext.c : raw text input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2009 the VideoLAN team
+ * $Id$
+ *
+ * Authors: Pierre Ynard
+ *          Denis Charmet
+ *
+ * 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 <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_demux.h>
+
+#include <vlc_network.h>
+#include <vlc_url.h>
+#include <vlc_fs.h>
+#ifdef HAVE_FCNTL_H
+#   include <fcntl.h>
+#endif
+#ifdef HAVE_POLL
+# include <poll.h>
+#endif
+
+#include <errno.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+
+#define FOURCC_TEXT N_("FOURCC code of raw input format")
+#define FOURCC_LONGTEXT N_( \
+    "FOURCC code of the raw input format. This is a four character string." )
+
+#define LANG_TEXT N_("Forces the subtitle language.")
+#define LANG_LONGTEXT N_("Forces the audio language for the output mux. Three letter ISO639 code. Default is 'eng'. ")
+
+#define SRC_TEXT N_("Input Source")
+#define SRC_LONGTEXT N_("Source from where the subtitles are retrieved")
+
+#define SEP_TEXT N_("Separator string")
+#define SEP_LONGTEXT N_("String which cuts subtitles into logical units")
+
+#define SCROLL_TEXT N_("Enable scrolling")
+#define SCROLL_LONGTEXT N_("Subtitles will scroll until the module recieves a separator")
+
+
+#define MAX_LINE_LENGTH 2048
+#define FOURCC_DEFAULT "subt"
+
+typedef enum
+{
+    ACC_TCP,
+    ACC_UDP,
+    ACC_FILE,
+    ACC_FD
+} access_type_t;
+
+vlc_module_begin();
+    set_shortname( "Raw Text" );
+    set_description( N_("Raw text subtitle demuxer") );
+    add_shortcut( "rawtext" )
+    set_capability( "access_demux", 0 );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_DEMUX );
+    set_callbacks( Open, Close );
+    add_shortcut( "rawtext" );
+    add_string( "rawtext-fourcc", FOURCC_DEFAULT, NULL,
+                FOURCC_TEXT, FOURCC_LONGTEXT, false );
+    add_string( "rawtext-lang", "eng", NULL, LANG_TEXT, LANG_LONGTEXT, false);
+    add_string( "rawtext-src", NULL, NULL, SRC_TEXT, SRC_LONGTEXT, false );
+    add_string( "rawtext-sep", NULL, NULL, SEP_TEXT, SEP_LONGTEXT, false);
+    add_bool( "rawtext-scrolling",false, NULL, SCROLL_TEXT, SCROLL_LONGTEXT, false);
+vlc_module_end();
+
+/*****************************************************************************
+ * Definitions of structures used by this plugin
+ *****************************************************************************/
+struct demux_sys_t
+{
+    es_out_id_t    *p_es;
+    es_format_t     fmt;
+    mtime_t         i_start;
+    FILE           *p_fs;
+    int             i_fd;
+    char           *p_subtitle;
+    vlc_thread_t    thread;
+    char           *psz_sep;
+    bool            b_scroll;
+};
+
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int Control( demux_t *, int i_query, va_list args );
+static void *rawtext_thread(void * data);
+
+/*****************************************************************************
+ * Open: initializes raw audio demuxer
+ *****************************************************************************/
+static int Open( vlc_object_t * p_this )
+{
+    demux_t     *p_demux = (demux_t*)p_this;
+    demux_sys_t *p_sys;
+    char * psz_src;
+    access_type_t access_type;
+
+    /* Set p_input field */
+    p_demux->pf_demux   = NULL;
+    p_demux->pf_control = Control;
+    p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
+    if( !p_sys )
+        return VLC_ENOMEM;
+
+    p_sys->p_subtitle = NULL;
+
+    es_format_Init( &p_sys->fmt, SPU_ES, 0 );
+
+    char *psz_fourcc = var_CreateGetString( p_demux, "rawtext-fourcc" );
+    p_sys->fmt.i_codec = vlc_fourcc_GetCodecFromString( SPU_ES, psz_fourcc );
+    free( psz_fourcc );
+
+    if( !p_sys->fmt.i_codec )
+    {
+        msg_Err( p_demux, "rawtext-fourcc must be a 4 character string");
+        es_format_Clean( &p_sys->fmt );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+
+    p_sys->b_scroll = var_CreateGetBool( p_demux, "rawtext-scrolling");
+
+    p_sys->fmt.psz_language = var_CreateGetString( p_demux, "rawtext-lang" );
+
+    msg_Dbg( p_demux, "format initialized: fourcc=%4.4s", (char*)&p_sys->fmt.i_codec);
+
+    p_sys->psz_sep = var_CreateGetString( p_demux, "rawtext-sep" );
+    if (p_sys->psz_sep == NULL)
+        p_sys->psz_sep = strdup("");
+    if (p_sys->psz_sep == NULL)
+    {
+        es_format_Clean( &p_sys->fmt );
+        free( p_sys );
+        return VLC_ENOMEM;
+    }
+
+
+    if (strlen(p_sys->psz_sep) > MAX_LINE_LENGTH)
+    {
+        msg_Err( p_demux, "separator too long!");
+        free(p_sys->psz_sep);
+        es_format_Clean( &p_sys->fmt );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+
+    psz_src = var_CreateGetString( p_demux, "rawtext-src");
+    if( ! psz_src )
+    {
+        msg_Err(p_demux, "Missing rawtext host");
+        free(p_sys->psz_sep);
+        es_format_Clean( &p_sys->fmt );
+        free(p_sys);
+        return VLC_EGENERIC;
+    }
+
+    vlc_url_t url;
+    vlc_UrlParse(&url, psz_src, 0);
+    free( psz_src );
+
+    const char *psz_host = url.psz_host != NULL ? url.psz_host : "localhost";
+
+    if( url.psz_protocol == NULL || !strcmp(url.psz_protocol,"tcp"))
+    {
+        msg_Dbg(p_demux, "Opening %s://%s:%d", "tcp",
+                                               psz_host, url.i_port);
+        p_sys->i_fd = net_ConnectTCP(p_demux, psz_host, url.i_port );
+        access_type = ACC_TCP;
+    }
+    else if(!strcmp(url.psz_protocol,"udp"))
+    {
+        msg_Dbg(p_demux, "Opening %s://%s:%d", url.psz_protocol,
+                                               psz_host, url.i_port);
+        p_sys->i_fd = net_ListenUDP1((vlc_object_t *) p_demux,
+                                     psz_host, url.i_port);
+        access_type = ACC_UDP;
+    }
+    else if(!strcmp(url.psz_protocol,"file"))
+    {
+        msg_Dbg(p_demux, "Opening %s://%s", url.psz_protocol,
+                                            url.psz_path);
+        p_sys->i_fd = vlc_open( url.psz_path, O_RDWR | O_NONBLOCK );
+        access_type = ACC_FILE;
+    }
+    else if(!strcmp(url.psz_protocol,"fd"))
+    {
+        p_sys->i_fd = atoi(url.psz_host);
+        msg_Dbg(p_demux, "Opening %s://%d", url.psz_protocol,
+                                            p_sys->i_fd);
+        access_type = ACC_FD;
+    }
+    else
+    {
+        msg_Err( p_demux, "Couldn't find appropriate access");
+
+        free(p_sys->psz_sep);
+        es_format_Clean( &p_sys->fmt );
+        vlc_UrlClean(&url);
+        free(p_sys);
+        return VLC_EGENERIC;
+    }
+
+    if ( p_sys->i_fd < 0)
+    {
+        msg_Err( p_demux, "Couldn't open: %m" );
+        free(p_sys->psz_sep);
+        es_format_Clean( &p_sys->fmt );
+        vlc_UrlClean(&url);
+        free(p_sys);
+        return VLC_EGENERIC;
+    }
+
+    p_sys->p_fs = fdopen( p_sys->i_fd, "r" );
+    if (p_sys->p_fs == NULL)
+    {
+        msg_Err( p_demux, "Couldn't fdopen: %m" );
+        switch( access_type )
+        {
+            case ACC_TCP:
+            case ACC_UDP:
+                net_Close(p_sys->i_fd);
+                break;
+            case ACC_FILE:
+            case ACC_FD:
+            default:
+                close( p_sys->i_fd );
+        }
+        es_format_Clean( &p_sys->fmt );
+        vlc_UrlClean(&url);
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+    vlc_UrlClean(&url);
+ 
+    p_sys->i_start = mdate();
+
+    /* add the es */
+    p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
+    msg_Dbg( p_demux, "elementary stream added");
+
+   if (vlc_clone (&p_sys->thread, rawtext_thread, p_demux,
+                   VLC_THREAD_PRIORITY_INPUT))
+    {
+        es_format_Clean( &p_sys->fmt );
+        free( p_sys );
+        fclose( p_sys->p_fs );
+        return VLC_EGENERIC;
+    }
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Close: frees unused data
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+    demux_t     *p_demux = (demux_t*)p_this;
+    demux_sys_t *p_sys  = p_demux->p_sys;
+
+    vlc_cancel (p_sys->thread);
+    vlc_join (p_sys->thread, NULL);
+
+    es_format_Clean( &p_sys->fmt );
+    fclose( p_sys->p_fs );
+    free( p_sys->p_subtitle );
+    free( p_sys->psz_sep );
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * rawtext_thread : Thread polling the input filestream
+ *****************************************************************************/
+static void *rawtext_thread(void * data)
+{
+    demux_t * p_demux = (demux_t *) data;
+    demux_sys_t *p_sys  = p_demux->p_sys;
+    block_t     *p_block;
+
+    char psz_line[MAX_LINE_LENGTH];
+
+    p_sys->p_subtitle = NULL;
+    size_t i_blocklen, i_sublen = 0;
+
+    struct pollfd rtfd = { .fd = p_sys->i_fd, .events = POLLIN, };
+    while ( poll( &rtfd, 1, -1 ) > 0 )
+    {
+        bool br = false;
+        msg_Dbg(p_demux,"rtfd.revents=%x",rtfd.revents);
+        if( rtfd.revents & POLLIN )
+        {
+            while( fgets( psz_line, MAX_LINE_LENGTH, p_sys->p_fs ) != NULL )
+            {
+                msg_Dbg( p_demux, "got line %s", psz_line);
+                size_t i_len = strlen(psz_line);
+
+                if (i_len > 0 && psz_line[i_len - 1] == '\n')
+                {
+                    psz_line[i_len - 1] = '\0';
+                    if (!strcmp(psz_line, p_sys->psz_sep))
+                    {
+                        br = true;
+                        break;
+                    }
+                    psz_line[i_len - 1] = '\n';
+                }
+                else
+                {
+                    if (!strcmp(psz_line, p_sys->psz_sep))
+                    {
+                        br = true;
+                        break;
+                    }
+                }
+
+                i_sublen += i_len;
+                if (p_sys->p_subtitle == NULL)
+                {
+                    p_sys->p_subtitle = strdup(psz_line);
+                }
+                else
+                {
+                    char *tmp = realloc(p_sys->p_subtitle, i_sublen + 1);
+                    if (tmp == NULL)
+                        return NULL;
+                    strcat(tmp, psz_line);
+                    p_sys->p_subtitle = tmp;
+                }
+            }
+
+            if (!br && p_sys->p_subtitle == NULL)
+                break;
+
+            i_blocklen = i_sublen - ((i_sublen > 0 && p_sys->p_subtitle[i_sublen - 1] == '\n')?1:0);
+
+            p_block = block_New(p_demux, i_blocklen);
+
+            memcpy(p_block->p_buffer, p_sys->p_subtitle, i_blocklen);
+
+            if(!p_sys->b_scroll || br)
+            {
+                free(p_sys->p_subtitle);
+                p_sys->p_subtitle = NULL;
+                i_sublen = 0;
+            }
+
+            p_block->i_dts = p_block->i_pts = mdate() - p_sys->i_start;
+            msg_Dbg( p_demux, "have sub time %"PRIu64, p_block->i_pts);
+
+            es_out_Control(p_demux->out, ES_OUT_SET_PCR, p_block->i_pts);
+            es_out_Send(p_demux->out, p_sys->p_es, p_block);
+
+            if (feof(p_sys->p_fs))
+                break;
+        }
+        if ( rtfd.revents & POLLHUP )
+        {
+            msg_Err( p_demux, "Polling failed (%m)");
+            break;
+        }
+    }
+    return NULL;
+}
+
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+    (void) p_demux;
+
+    switch (i_query)
+    {
+    case DEMUX_CAN_PAUSE:
+    case DEMUX_CAN_CONTROL_PACE: {
+        bool *b = va_arg(args, bool *);
+        *b = false;
+        return VLC_SUCCESS;
+    }
+    case DEMUX_SET_PAUSE_STATE:
+        return VLC_SUCCESS;
+
+    case DEMUX_GET_POSITION: {
+        double *position = va_arg(args, double *);
+        *position = 0.0;
+        return VLC_SUCCESS;
+    }
+
+    case DEMUX_GET_TIME:
+    case DEMUX_GET_LENGTH: {
+        int64_t *t = va_arg(args, int64_t *);
+        *t = 0;
+        return VLC_SUCCESS;
+    }
+    case DEMUX_SET_NEXT_DEMUX_TIME:
+        return VLC_SUCCESS;
+
+    case DEMUX_GET_PTS_DELAY: {
+        int * i = va_arg(args, int *);
+        *i = 0;
+        return VLC_SUCCESS;
+    }
+    /* */
+    case DEMUX_CAN_SEEK:
+    case DEMUX_SET_POSITION:
+    case DEMUX_SET_TIME:
+    default:
+        return VLC_EGENERIC;
+    }
+
+    return VLC_EGENERIC;
+}
diff --git a/modules/demux/Modules.am b/modules/demux/Modules.am
index f47739e..476d0bf 100644
--- a/modules/demux/Modules.am
+++ b/modules/demux/Modules.am
@@ -4,6 +4,7 @@ SOURCES_ogg = ogg.c vorbis.h kate_categories.c
kate_categories.h xiph.h
 SOURCES_demuxdump = demuxdump.c
 SOURCES_rawdv = rawdv.c
 SOURCES_rawvid = rawvid.c
+SOURCES_rawtext = rawtext.c
 SOURCES_au = au.c
 SOURCES_rawaud = rawaud.c
 SOURCES_wav = wav.c
@@ -36,6 +37,7 @@ libvlc_LTLIBRARIES += \
        libaiff_plugin.la \
        libau_plugin.la \
        librawaud_plugin.la \
+       librawtext_plugin.la \
        libdirac_plugin.la \
        libdemux_cdg_plugin.la \
        libdemuxdump_plugin.la \ 



More information about the vlc-devel mailing list