[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