[vlc-commits] codec: ttml: handle EN 303 560 payload
Francois Cartegnie
git at videolan.org
Thu Jul 19 11:08:42 CEST 2018
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Jul 18 14:38:14 2018 +0200| [11825ed7f2975e5e78fbb7d27f8370bd8602e145] | committer: Francois Cartegnie
codec: ttml: handle EN 303 560 payload
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=11825ed7f2975e5e78fbb7d27f8370bd8602e145
---
modules/codec/Makefile.am | 3 +-
modules/codec/ttml/substtml.c | 49 ++++++++++++---
modules/codec/ttml/ttmlpes.h | 135 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+), 8 deletions(-)
diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index 379c50833f..9ff8166bf0 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -226,7 +226,8 @@ codec_LTLIBRARIES += libsubsusf_plugin.la
libttml_plugin_la_SOURCES = codec/ttml/substtml.c \
demux/ttml.c \
codec/ttml/ttml.h codec/ttml/ttml.c \
- codec/ttml/imageupdater.h
+ codec/ttml/imageupdater.h \
+ codec/ttml/ttmlpes.h
codec_LTLIBRARIES += libttml_plugin.la
libwebvtt_plugin_la_SOURCES = codec/webvtt/subsvtt.c \
diff --git a/modules/codec/ttml/substtml.c b/modules/codec/ttml/substtml.c
index b66a3df5e0..084113d3ef 100644
--- a/modules/codec/ttml/substtml.c
+++ b/modules/codec/ttml/substtml.c
@@ -38,6 +38,7 @@
#include "substext.h"
#include "ttml.h"
#include "imageupdater.h"
+#include "ttmlpes.h"
//#define TTML_DEBUG
@@ -60,6 +61,7 @@ typedef struct
#define TTML_DEFAULT_CELL_RESOLUTION_V 15
#define TTML_LINE_TO_HEIGHT_RATIO 1.06
+
typedef struct
{
text_style_t* font_style;
@@ -103,6 +105,7 @@ typedef struct
typedef struct
{
int i_align;
+ struct ttml_in_pes_ctx pes;
} decoder_sys_t;
enum
@@ -1215,6 +1218,8 @@ static void TTMLRegionsToSpuBitmapRegions( decoder_t *p_dec, subpicture_t *p_spu
static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
tt_time_t *p_timings_array = NULL;
size_t i_timings_count = 0;
@@ -1248,16 +1253,24 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
printf("%ld ", tt_time_Convert( &p_timings_array[i] ) );
printf("\n");
#endif
+ vlc_tick_t i_block_start_time = p_block->i_dts - p_sys->pes.i_offset;
+
+ if(TTML_in_PES(p_dec) && i_block_start_time < p_sys->pes.i_prev_segment_start_time )
+ i_block_start_time = p_sys->pes.i_prev_segment_start_time;
for( size_t i=0; i+1 < i_timings_count; i++ )
{
/* We Only support absolute timings (2) */
- if( tt_time_Convert( &p_timings_array[i] ) + VLC_TICK_0 < p_block->i_dts )
+ if( tt_time_Convert( &p_timings_array[i] ) + VLC_TICK_0 < i_block_start_time )
continue;
- if( tt_time_Convert( &p_timings_array[i] ) + VLC_TICK_0 > p_block->i_dts + p_block->i_length )
+ if( !TTML_in_PES(p_dec) &&
+ tt_time_Convert( &p_timings_array[i] ) + VLC_TICK_0 > i_block_start_time + p_block->i_length )
break;
+ if( TTML_in_PES(p_dec) && p_sys->pes.i_prev_segment_start_time < tt_time_Convert( &p_timings_array[i] ) )
+ p_sys->pes.i_prev_segment_start_time = tt_time_Convert( &p_timings_array[i] );
+
bool b_bitmap_regions = false;
subpicture_t *p_spu = NULL;
ttml_region_t *p_regions = GenerateRegions( p_rootnode, p_timings_array[i] );
@@ -1276,8 +1289,10 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
if( p_regions && p_spu )
{
- p_spu->i_start = VLC_TICK_0 + tt_time_Convert( &p_timings_array[i] );
- p_spu->i_stop = VLC_TICK_0 + tt_time_Convert( &p_timings_array[i+1] ) - 1;
+ p_spu->i_start = p_sys->pes.i_offset +
+ VLC_TICK_0 + tt_time_Convert( &p_timings_array[i] );
+ p_spu->i_stop = p_sys->pes.i_offset +
+ VLC_TICK_0 + tt_time_Convert( &p_timings_array[i+1] ) - 1;
p_spu->b_ephemer = true;
p_spu->b_absolute = true;
@@ -1307,7 +1322,6 @@ static int ParseBlock( decoder_t *p_dec, const block_t *p_block )
}
-
/****************************************************************************
* DecodeBlock: the whole thing
****************************************************************************/
@@ -1328,6 +1342,21 @@ static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
return ret;
}
+static int DecodePESBlock( decoder_t *p_dec, block_t *p_block )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ return ParsePESEncap( p_dec, &p_sys->pes, DecodeBlock, p_block );
+}
+
+/*****************************************************************************
+ * Flush state between seeks
+ *****************************************************************************/
+static void Flush( decoder_t *p_dec )
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ ttml_in_pes_Init( &p_sys->pes );
+}
+
/*****************************************************************************
* tt_OpenDecoder: probe the decoder and return score
*****************************************************************************/
@@ -1336,7 +1365,8 @@ int tt_OpenDecoder( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
- if( p_dec->fmt_in.i_codec != VLC_CODEC_TTML )
+ if( p_dec->fmt_in.i_codec != VLC_CODEC_TTML &&
+ !TTML_in_PES(p_dec) )
return VLC_EGENERIC;
/* Allocate the memory needed to store the decoder's structure */
@@ -1344,8 +1374,13 @@ int tt_OpenDecoder( vlc_object_t *p_this )
if( unlikely( p_sys == NULL ) )
return VLC_ENOMEM;
- p_dec->pf_decode = DecodeBlock;
+ if( !TTML_in_PES( p_dec ) )
+ p_dec->pf_decode = DecodeBlock;
+ else
+ p_dec->pf_decode = DecodePESBlock;
+ p_dec->pf_flush = Flush;
p_sys->i_align = var_InheritInteger( p_dec, "ttml-align" );
+ ttml_in_pes_Init( &p_sys->pes );
return VLC_SUCCESS;
}
diff --git a/modules/codec/ttml/ttmlpes.h b/modules/codec/ttml/ttmlpes.h
new file mode 100644
index 0000000000..6180fac47e
--- /dev/null
+++ b/modules/codec/ttml/ttmlpes.h
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * ttmlpes.c : TTML subtitles in EN 303 560 payload
+ *****************************************************************************
+ * Copyright (C) 2018 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.
+ *****************************************************************************/
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+#include <vlc_stream.h>
+
+enum
+{
+ TTML_UNCOMPRESSED_DOCUMENT = 0x01,
+ TTML_GZIP_COMPRESSED_DOCUMENT = 0x02,
+};
+
+struct ttml_in_pes_ctx
+{
+ int64_t i_offset; /* relative segment offset to apply */
+ vlc_tick_t i_prev_block_time; /* because blocks are duplicated */
+ vlc_tick_t i_prev_segment_start_time; /* because content can overlap */
+};
+
+static void ttml_in_pes_Init(struct ttml_in_pes_ctx *p)
+{
+ p->i_offset = 0;
+ p->i_prev_block_time = -1;
+ p->i_prev_segment_start_time = -1;
+}
+
+static inline bool TTML_in_PES(decoder_t *p_dec)
+{
+ return p_dec->fmt_in.i_codec == VLC_CODEC_TTML_TS;
+}
+
+static block_t * DecompressTTML( decoder_t *p_dec, const uint8_t *p_data, size_t i_data )
+{
+ block_t *p_decomp = NULL;
+ block_t **pp_append = &p_decomp;
+
+ stream_t *s = vlc_stream_MemoryNew( p_dec, (uint8_t *) p_data, i_data, true );
+ if( !s )
+ return NULL;
+ stream_t *p_inflate = vlc_stream_FilterNew( s, "inflate" );
+ if( p_inflate )
+ {
+ for( ;; )
+ {
+ *pp_append = vlc_stream_Block( p_inflate, 64 * 1024 );
+ if( *pp_append == NULL ||
+ (*pp_append)->i_buffer < 64*1024 )
+ break;
+ pp_append = &((*pp_append)->p_next);
+ }
+ s = p_inflate;
+ }
+ vlc_stream_Delete( s );
+ return p_decomp ? block_ChainGather( p_decomp ) : NULL;
+}
+
+static int ParsePESEncap( decoder_t *p_dec,
+ struct ttml_in_pes_ctx *p_ctx,
+ int(*pf_decode)(decoder_t *, block_t *),
+ block_t *p_block )
+{
+ if( p_block == NULL ) /* No Drain */
+ return VLCDEC_SUCCESS;
+
+ if( p_block->i_buffer < 7 )
+ {
+ block_Release( p_block );
+ return VLC_EGENERIC;
+ }
+
+ if( p_block->i_dts == p_ctx->i_prev_block_time )
+ {
+ block_Release( p_block );
+ return VLC_SUCCESS;
+ }
+
+ int64_t i_segment_base = GetDWBE(p_block->p_buffer);
+ i_segment_base = (i_segment_base << 16) | GetWBE(&p_block->p_buffer[4]);
+ i_segment_base *= 100;
+ uint8_t i_num_segments = p_block->p_buffer[6];
+ size_t i_data = p_block->i_buffer - 7;
+ const uint8_t *p_data = &p_block->p_buffer[7];
+ p_ctx->i_offset = (p_block->i_dts - VLC_TICK_0) - i_segment_base;
+ for( uint8_t i=0; i<i_num_segments; i++ )
+ {
+ if( i_data < 3 )
+ break;
+ uint8_t i_type = p_data[0];
+ uint16_t i_size = GetWBE(&p_data[1]);
+ if( i_size > i_data - 3 )
+ break;
+ block_t *p_segment = NULL;
+ if( i_type == TTML_UNCOMPRESSED_DOCUMENT )
+ {
+ p_segment = block_Alloc( i_size );
+ if( p_segment )
+ memcpy( p_segment->p_buffer, &p_data[3], i_size );
+ }
+ else if( i_type == TTML_GZIP_COMPRESSED_DOCUMENT )
+ {
+ p_segment = DecompressTTML( p_dec, &p_data[3], i_size );
+ }
+
+ if( p_segment )
+ {
+ block_CopyProperties( p_segment, p_block );
+ pf_decode( p_dec, p_segment );
+ }
+
+ p_data += 3 + i_size;
+ i_data -= 3 + i_size;
+ }
+
+ p_ctx->i_prev_block_time = p_block->i_dts;
+ block_Release( p_block );
+ return VLC_SUCCESS;
+}
More information about the vlc-commits
mailing list