[vlc-commits] demux: subtitle: add support for SCC
Francois Cartegnie
git at videolan.org
Tue Aug 29 08:42:45 CEST 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Aug 28 21:34:57 2017 +0200| [f97ba7b82dcf3b2964d8e990398f94ba43b93369] | committer: Francois Cartegnie
demux: subtitle: add support for SCC
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f97ba7b82dcf3b2964d8e990398f94ba43b93369
---
NEWS | 1 +
include/vlc_input_item.h | 3 +-
modules/demux/subtitle.c | 133 +++++++++++++++++++++++++++++++++++++++--------
3 files changed, 115 insertions(+), 22 deletions(-)
diff --git a/NEWS b/NEWS
index 9eece2102a..fd309e300b 100644
--- a/NEWS
+++ b/NEWS
@@ -129,6 +129,7 @@ Demuxers:
* Support multi-channel WAV without channel-maps
* Rewrite MKV seeking
* Support for TTML and WebVTT in ISOBMF/MP4 and DASH
+ * Support for Scenarist Closed Caption
* Fix Quicktime Mp4 inside MKV and unpacketized VC1
* Support for isofLaC
* Improved fLaC seeking
diff --git a/include/vlc_input_item.h b/include/vlc_input_item.h
index d820a9fc95..5656dc6c2c 100644
--- a/include/vlc_input_item.h
+++ b/include/vlc_input_item.h
@@ -149,7 +149,8 @@ enum slave_priority
"usf", "jss", "cdg", \
"psb", "mpsub","mpl2", \
"pjs", "dks", "stl", \
- "vtt", "sbv", "ttml"
+ "vtt", "sbv", "ttml" \
+ "scc"
#define SLAVE_AUDIO_EXTENSIONS \
"ac3", "m4a", "aac", \
"eac3", "dtshd", "flac", \
diff --git a/modules/demux/subtitle.c b/modules/demux/subtitle.c
index fd3b7b77a2..fbd6ef4b6d 100644
--- a/modules/demux/subtitle.c
+++ b/modules/demux/subtitle.c
@@ -115,7 +115,8 @@ enum subtitle_type_e
SUB_TYPE_SUBVIEW1, /* SUBVIEWER 1 - mplayer calls it subrip09,
and Gnome subtitles SubViewer 1.0 */
SUB_TYPE_VTT,
- SUB_TYPE_SBV
+ SUB_TYPE_SBV,
+ SUB_TYPE_SCC, /* Scenarist Closed Caption */
};
typedef struct
@@ -181,6 +182,8 @@ struct demux_sys_t
/* */
subs_properties_t props;
+
+ block_t * (*pf_convert)( const subtitle_t * );
};
static int ParseMicroDvd ( vlc_object_t *, subs_properties_t *, text_t *, subtitle_t *, size_t );
@@ -200,6 +203,7 @@ static int ParseRealText ( vlc_object_t *, subs_properties_t *, text_t *, sub
static int ParseDKS ( vlc_object_t *, subs_properties_t *, text_t *, subtitle_t *, size_t );
static int ParseSubViewer1 ( vlc_object_t *, subs_properties_t *, text_t *, subtitle_t *, size_t );
static int ParseCommonVTTSBV( vlc_object_t *, subs_properties_t *, text_t *, subtitle_t *, size_t );
+static int ParseSCC ( vlc_object_t *, subs_properties_t *, text_t *, subtitle_t *, size_t );
static const struct
{
@@ -229,6 +233,7 @@ static const struct
{ "subviewer1", SUB_TYPE_SUBVIEW1, "Subviewer 1", ParseSubViewer1 },
{ "text/vtt", SUB_TYPE_VTT, "WebVTT", ParseCommonVTTSBV },
{ "sbv", SUB_TYPE_SBV, "SBV", ParseCommonVTTSBV },
+ { "scc", SUB_TYPE_SCC, "SCC", ParseSCC },
{ NULL, SUB_TYPE_UNKNOWN, "Unknown", NULL }
};
/* When adding support for more formats, be sure to add their file extension
@@ -242,6 +247,52 @@ static void Fix( demux_t * );
static char * get_language_from_filename( const char * );
/*****************************************************************************
+ * Decoder format output function
+ *****************************************************************************/
+
+static block_t *ToTextBlock( const subtitle_t *p_subtitle )
+{
+ block_t *p_block;
+ size_t i_len = strlen( p_subtitle->psz_text ) + 1;
+
+ if( i_len <= 1 || !(p_block = block_Alloc( i_len )) )
+ return NULL;
+
+ memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
+
+ return p_block;
+}
+
+static block_t *ToEIA608Block( const subtitle_t *p_subtitle )
+{
+ block_t *p_block;
+ const size_t i_len = strlen( p_subtitle->psz_text );
+ const size_t i_block = (1 + i_len / 5) * 3;
+
+ if( i_len < 4 || !(p_block = block_Alloc( i_block )) )
+ return NULL;
+
+ p_block->i_buffer = 0;
+
+ char *saveptr = NULL;
+ char *psz_tok = strtok_r( p_subtitle->psz_text, " ", &saveptr );
+ unsigned a, b;
+ while( psz_tok &&
+ sscanf( psz_tok, "%2x%2x", &a, &b ) == 2 &&
+ i_block - p_block->i_buffer >= 3 )
+ {
+ uint8_t *p_data = &p_block->p_buffer[p_block->i_buffer];
+ p_data[0] = 0xFC;
+ p_data[1] = a;
+ p_data[2] = b;
+ p_block->i_buffer += 3;
+ psz_tok = strtok_r( NULL, " ", &saveptr );
+ }
+
+ return p_block;
+}
+
+/*****************************************************************************
* Module initializer
*****************************************************************************/
static int Open ( vlc_object_t *p_this )
@@ -269,6 +320,8 @@ static int Open ( vlc_object_t *p_this )
p_sys->b_first_time = true;
p_sys->i_next_demux_date = 0;
+ p_sys->pf_convert = ToTextBlock;
+
p_sys->subtitles.i_current= 0;
p_sys->subtitles.i_count = 0;
p_sys->subtitles.p_array = NULL;
@@ -565,6 +618,12 @@ static int Open ( vlc_object_t *p_this )
p_sys->props.i_type = SUB_TYPE_VTT;
break;
}
+ else if( !strncasecmp( s, "Scenarist_SCC V1.0", 18 ) )
+ {
+ p_sys->props.i_type = SUB_TYPE_SCC;
+ p_sys->pf_convert = ToEIA608Block;
+ break;
+ }
free( s );
s = NULL;
@@ -653,6 +712,10 @@ static int Open ( vlc_object_t *p_this )
Fix( p_demux );
es_format_Init( &fmt, SPU_ES, VLC_CODEC_SSA );
}
+ else if( p_sys->props.i_type == SUB_TYPE_SCC )
+ {
+ es_format_Init( &fmt, SPU_ES, VLC_CODEC_EIA608_1 );
+ }
else
es_format_Init( &fmt, SPU_ES, VLC_CODEC_SUBT );
@@ -816,30 +879,20 @@ static int Demux( demux_t *p_demux )
p_sys->b_first_time = false;
}
- block_t *p_block;
- size_t i_len = strlen( p_subtitle->psz_text ) + 1;
-
- if( i_len <= 1 || p_subtitle->i_start < 0 )
+ if( p_subtitle->i_start >= 0 )
{
- p_sys->subtitles.i_current++;
- continue;
- }
+ block_t *p_block = p_sys->pf_convert( p_subtitle );
+ if( p_block )
+ {
+ p_block->i_dts =
+ p_block->i_pts = VLC_TS_0 + p_subtitle->i_start;
+ if( p_subtitle->i_stop >= 0 && p_subtitle->i_stop >= p_subtitle->i_start )
+ p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
- if( ( p_block = block_Alloc( i_len ) ) == NULL )
- {
- p_sys->subtitles.i_current++;
- continue;
+ es_out_Send( p_demux->out, p_sys->es, p_block );
+ }
}
- p_block->i_dts =
- p_block->i_pts = VLC_TS_0 + p_subtitle->i_start;
- if( p_subtitle->i_stop >= 0 && p_subtitle->i_stop >= p_subtitle->i_start )
- p_block->i_length = p_subtitle->i_stop - p_subtitle->i_start;
-
- memcpy( p_block->p_buffer, p_subtitle->psz_text, i_len );
-
- es_out_Send( p_demux->out, p_sys->es, p_block );
-
p_sys->subtitles.i_current++;
}
@@ -2355,6 +2408,44 @@ static int ParseCommonVTTSBV( vlc_object_t *p_obj, subs_properties_t *p_props,
}
}
+static int ParseSCC( vlc_object_t *p_obj, subs_properties_t *p_props,
+ text_t *txt, subtitle_t *p_subtitle, size_t i_idx )
+{
+ VLC_UNUSED(p_obj);
+ VLC_UNUSED( i_idx );
+ VLC_UNUSED( p_props );
+
+ for( ;; )
+ {
+ const char *psz_line = TextGetLine( txt );
+ if( !psz_line )
+ return VLC_EGENERIC;
+
+ unsigned h, m, s, f;
+ if( sscanf( psz_line, "%u:%u:%u:%u ", &h, &m, &s, &f ) != 4 )
+ continue;
+
+ p_subtitle->i_start = CLOCK_FREQ * ( h * 3600 + m * 60 + s ) +
+ f * p_props->i_microsecperframe;
+ p_subtitle->i_stop = -1;
+
+ const char *psz_text = strchr( psz_line, '\t' );
+ if( !psz_text && !(psz_text = strchr( psz_line, ' ' )) )
+ continue;
+
+ if ( psz_text[1] == '\0' )
+ continue;
+
+ p_subtitle->psz_text = strdup( psz_text + 1 );
+ if( !p_subtitle->psz_text )
+ return VLC_ENOMEM;
+
+ break;
+ }
+
+ return VLC_SUCCESS;
+}
+
/* Matches filename.xx.srt */
static char * get_language_from_filename( const char * psz_sub_file )
{
More information about the vlc-commits
mailing list