Browse Source

codec: add WEBVTT decoder

pull/59/merge
Francois Cartegnie 9 years ago
parent
commit
1e11cfda2c
  1. 1
      modules/MODULES_LIST
  2. 6
      modules/codec/Makefile.am
  3. 1137
      modules/codec/webvtt/subsvtt.c
  4. 249
      modules/codec/webvtt/webvtt.c
  5. 71
      modules/codec/webvtt/webvtt.h
  6. 55
      modules/demux/mp4/minibox.h

1
modules/MODULES_LIST

@ -460,6 +460,7 @@ $Id$
* wav: Wav demuxer
* wave: Wave video effect
* waveout: simple audio output module for Windows
* webvtt: WEBVTT subtitles decoder
* wgl: WGL extension for OpenGL
* win_hotkeys: module to catch hotkeys when application doesn't have the focus
* win_msg: Windows Messages module

6
modules/codec/Makefile.am

@ -222,6 +222,12 @@ libttml_plugin_la_SOURCES = codec/ttml/substtml.c \
codec/ttml/ttml.h codec/ttml/ttml.c
codec_LTLIBRARIES += libttml_plugin.la
libwebvtt_plugin_la_SOURCES = codec/webvtt/subsvtt.c \
codec/webvtt/webvtt.c \
codec/webvtt/webvtt.h \
demux/mp4/minibox.h
codec_LTLIBRARIES += libwebvtt_plugin.la
libsvcdsub_plugin_la_SOURCES = codec/svcdsub.c
codec_LTLIBRARIES += libsvcdsub_plugin.la

1137
modules/codec/webvtt/subsvtt.c

File diff suppressed because it is too large

249
modules/codec/webvtt/webvtt.c

@ -0,0 +1,249 @@
/*****************************************************************************
* webvtt.c: WEBVTT shared code
*****************************************************************************
* Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_charset.h>
#include <vlc_plugin.h>
#include "webvtt.h"
#include <ctype.h>
#include <assert.h>
/*****************************************************************************
* Modules descriptor.
*****************************************************************************/
vlc_module_begin ()
set_capability( "spu decoder", 10 )
set_shortname( N_("WEBVTT decoder"))
set_description( N_("WEBVTT subtitles decoder") )
set_callbacks( OpenDecoder, CloseDecoder )
set_category( CAT_INPUT )
set_subcategory( SUBCAT_INPUT_SCODEC )
vlc_module_end ()
struct webvtt_text_parser_t
{
enum
{
WEBVTT_SECTION_UNDEFINED = WEBVTT_HEADER_STYLE - 1,
WEBVTT_SECTION_STYLE = WEBVTT_HEADER_STYLE,
WEBVTT_SECTION_REGION = WEBVTT_HEADER_REGION,
WEBVTT_SECTION_CUES,
} section;
char * reads[3];
void * priv;
webvtt_cue_t *(*pf_get_cue)( void * );
void (*pf_cue_done)( void *, webvtt_cue_t * );
void (*pf_header)( void *, enum webvtt_header_line_e, bool, const char * );
webvtt_cue_t *p_cue;
};
static mtime_t MakeTime( unsigned t[4] )
{
return t[0] * 3600 * CLOCK_FREQ +
t[1] * 60 * CLOCK_FREQ +
t[2] * CLOCK_FREQ +
t[3] * 1000;
}
bool webvtt_scan_time( const char *psz, mtime_t *p_time )
{
unsigned t[4];
if( sscanf( psz, "%2u:%2u.%3u",
&t[1], &t[2], &t[3] ) == 3 )
{
t[0] = 0;
*p_time = MakeTime( t );
return true;
}
else if( sscanf( psz, "%2u:%2u:%2u.%3u",
&t[0], &t[1], &t[2], &t[3] ) == 4 )
{
*p_time = MakeTime( t );
return true;
}
else return false;
}
static bool KeywordMatch( const char *psz, const char *keyword )
{
const size_t i_len = strlen(keyword);
return( !strncmp( keyword, psz, i_len ) && (!psz[i_len] || isspace(psz[i_len])) );
}
/*
*/
webvtt_text_parser_t * webvtt_text_parser_New( void *priv,
webvtt_cue_t *(*pf_get_cue)( void * ),
void (*pf_cue_done)( void *, webvtt_cue_t * ),
void (*pf_header)( void *, enum webvtt_header_line_e, bool, const char * ) )
{
webvtt_text_parser_t *p = malloc(sizeof(*p));
if( p )
{
p->section = WEBVTT_SECTION_UNDEFINED;
for( int i=0; i<3; i++ )
p->reads[i] = NULL;
p->p_cue = NULL;
p->priv = priv;
p->pf_cue_done = pf_cue_done;
p->pf_get_cue = pf_get_cue;
p->pf_header = pf_header;
}
return p;
}
void webvtt_text_parser_Delete( webvtt_text_parser_t *p )
{
for( int i=0; i<3; i++ )
free( p->reads[i] );
free( p );
}
static void forward_line( webvtt_text_parser_t *p, const char *psz_line, bool b_new )
{
if( p->pf_header )
p->pf_header( p->priv, p->section, b_new, psz_line );
}
void webvtt_text_parser_Feed( webvtt_text_parser_t *p, char *psz_line )
{
if( psz_line == NULL )
{
if( p->p_cue )
{
if( p->pf_cue_done )
p->pf_cue_done( p->priv, p->p_cue );
p->p_cue = NULL;
}
return;
}
free(p->reads[0]);
p->reads[0] = p->reads[1];
p->reads[1] = p->reads[2];
p->reads[2] = psz_line;
/* Lookup keywords */
if( unlikely(p->section == WEBVTT_SECTION_UNDEFINED) )
{
if( KeywordMatch( psz_line, "\xEF\xBB\xBFWEBVTT" ) ||
KeywordMatch( psz_line, "WEBVTT" ) )
{
p->section = WEBVTT_SECTION_UNDEFINED;
if( p->p_cue )
{
if( p->pf_cue_done )
p->pf_cue_done( p->priv, p->p_cue );
p->p_cue = NULL;
}
return;
}
else if( KeywordMatch( psz_line, "STYLE" ) )
{
p->section = WEBVTT_SECTION_STYLE;
forward_line( p, psz_line, true );
return;
}
else if( KeywordMatch( psz_line, "REGION" ) )
{
p->section = WEBVTT_SECTION_REGION;
forward_line( p, psz_line, true );
return;
}
else if( KeywordMatch( psz_line, "NOTE" ) )
{
return;
}
else if( psz_line[0] != 0 )
{
p->section = WEBVTT_SECTION_CUES;
}
}
if( likely(p->section == WEBVTT_SECTION_CUES) )
{
if( p->p_cue )
{
if( psz_line[0] == 0 )
{
p->p_cue = NULL;
}
else
{
char *psz_merged;
if( -1 < asprintf( &psz_merged, "%s\n%s", p->p_cue->psz_text, psz_line ) )
{
free( p->p_cue->psz_text );
p->p_cue->psz_text = psz_merged;
}
return;
}
}
if( p->reads[1] == NULL )
return;
const char *psz_split = strstr( p->reads[1], " --> " );
if( psz_split )
{
mtime_t i_start, i_stop;
if( webvtt_scan_time( p->reads[1], &i_start ) &&
webvtt_scan_time( psz_split + 5, &i_stop ) )
{
const char *psz_attrs = strchr( psz_split + 5 + 9, ' ' );
p->p_cue = ( p->pf_get_cue ) ? p->pf_get_cue( p->priv ) : NULL;
if( p->p_cue )
{
p->p_cue->psz_attrs = ( psz_attrs ) ? strdup( psz_attrs ) : NULL;
p->p_cue->psz_id = p->reads[0];
p->reads[0] = NULL;
p->p_cue->psz_text = p->reads[2];
p->reads[2] = NULL;
p->p_cue->i_start = i_start;
p->p_cue->i_stop = i_stop;
}
}
}
}
else if( p->section == WEBVTT_SECTION_STYLE )
{
forward_line( p, psz_line, false );
if( psz_line[0] == 0 )
p->section = WEBVTT_SECTION_UNDEFINED;
}
else if( p->section == WEBVTT_SECTION_REGION )
{
forward_line( p, psz_line, false );
if( psz_line[0] == 0 ) /* End of region declaration */
p->section = WEBVTT_SECTION_UNDEFINED;
}
}

71
modules/codec/webvtt/webvtt.h

@ -0,0 +1,71 @@
/*****************************************************************************
* webvtt.h: WEBVTT shared code
*****************************************************************************
* Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
*
* 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.
*****************************************************************************/
#ifndef WEBVTT_H
#define WEBVTT_H
int OpenDecoder ( vlc_object_t * );
void CloseDecoder ( vlc_object_t * );
typedef struct webvtt_text_parser_t webvtt_text_parser_t;
enum webvtt_header_line_e
{
WEBVTT_HEADER_STYLE = 1,
WEBVTT_HEADER_REGION,
};
typedef struct
{
mtime_t i_start;
mtime_t i_stop;
char *psz_id;
char *psz_text;
char *psz_attrs;
} webvtt_cue_t;
static inline void webvtt_cue_Init( webvtt_cue_t *c )
{
memset( c, 0, sizeof(*c) );
}
static inline void webvtt_cue_Clean( webvtt_cue_t *c )
{
free( c->psz_attrs );
free( c->psz_text );
free( c->psz_id );
}
webvtt_text_parser_t * webvtt_text_parser_New(
void *priv,
/* parser callback requesting a new cue to fill
* set to NULL if no cues data required */
webvtt_cue_t *(*pf_get_cue)( void * ),
/* callback when cue is complete set to NULL for no callback */
void (*pf_cue_done)( void *, webvtt_cue_t * ),
/* parser callback returning headers
* set to NULL for no callbacks */
void (*pf_header)( void *, enum webvtt_header_line_e, bool, const char * )
);
void webvtt_text_parser_Delete( webvtt_text_parser_t *p );
void webvtt_text_parser_Feed( webvtt_text_parser_t *p, char *psz_line );
bool webvtt_scan_time( const char *psz, mtime_t *p_time );
#endif

55
modules/demux/mp4/minibox.h

@ -0,0 +1,55 @@
/*****************************************************************************
* minibox.h: minimal mp4 box iterator
*****************************************************************************
* Copyright (C) 2017 VideoLabs, VLC authors and VideoLAN
*
* 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.
*****************************************************************************/
typedef struct
{
const uint8_t *p_buffer;
size_t i_buffer;
const uint8_t *p_payload;
size_t i_payload;
vlc_fourcc_t i_type;
} mp4_box_iterator_t;
static void mp4_box_iterator_Init( mp4_box_iterator_t *p_it,
const uint8_t *p_data, size_t i_data )
{
p_it->p_buffer = p_data;
p_it->i_buffer = i_data;
}
static bool mp4_box_iterator_Next( mp4_box_iterator_t *p_it )
{
while( p_it->i_buffer > 8 )
{
const uint8_t *p = p_it->p_buffer;
const size_t i_size = GetDWBE( p );
p_it->i_type = VLC_FOURCC(p[4], p[5], p[6], p[7]);
if( i_size >= 8 && i_size <= p_it->i_buffer )
{
p_it->p_payload = &p_it->p_buffer[8];
p_it->i_payload = i_size - 8;
/* update for next run */
p_it->p_buffer += i_size;
p_it->i_buffer -= i_size;
return true;
}
}
return false;
}
Loading…
Cancel
Save