[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