[vlc-devel] [PATCH 2/3] codec: add SMPTE-436m decoder

Francois Cartegnie fcvlcdev at free.fr
Tue Sep 26 23:24:26 CEST 2017


---
 modules/codec/Makefile.am |   3 +
 modules/codec/s436m.c     | 206 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 209 insertions(+)
 create mode 100644 modules/codec/s436m.c

diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
index da49a07..b5bca51 100644
--- a/modules/codec/Makefile.am
+++ b/modules/codec/Makefile.am
@@ -472,6 +472,9 @@ if HAVE_ANDROID
 codec_LTLIBRARIES += libiomx_plugin.la libmediacodec_plugin.la
 endif
 
+### DATA decoders ###
+libs436m_plugin_la_SOURCES = codec/s436m.c
+codec_LTLIBRARIES += libs436m_plugin.la
 
 ### X26x encoders ###
 
diff --git a/modules/codec/s436m.c b/modules/codec/s436m.c
new file mode 100644
index 0000000..da29743
--- /dev/null
+++ b/modules/codec/s436m.c
@@ -0,0 +1,206 @@
+/*****************************************************************************
+ * s436m.c : SMPTE-436m data decoder
+ *****************************************************************************
+ * Copyright © 2017 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.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+
+#include "cc.h"
+
+/*****************************************************************************
+ * Module descriptor.
+ *****************************************************************************/
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin ()
+    set_shortname( "S436m" )
+    set_description( "S436m" )
+    set_capability( "data decoder", 50 )
+    set_category( CAT_INPUT )
+        set_subcategory( SUBCAT_INPUT_SCODEC )
+    set_callbacks( Open, Close )
+
+vlc_module_end ()
+
+/*****************************************************************************
+ * Local
+ *****************************************************************************/
+static void ParseCC( decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
+                     uint8_t i_count, mtime_t i_dts,  mtime_t i_pts )
+{
+    cc_data_t cc;
+    cc_Init( &cc );
+    while( i_count-- > 0 && i_data > 2 )
+    {
+        cc_AppendData( &cc, p_data[0], &p_data[1] );
+        p_data += 3;
+        i_data -= 3;
+    }
+
+    if( cc.i_data > 0 )
+    {
+        block_t *p_block = block_Alloc( cc.i_data );
+        if( p_block )
+        {
+            p_block->i_dts = i_dts;
+            p_block->i_pts = i_pts;
+            memcpy( p_block->p_buffer, cc.p_data, cc.i_data );
+            decoder_QueueCc( p_dec, p_block, cc.pb_present, -1 );
+        }
+        cc_Flush( &cc );
+    }
+}
+
+static void ParseVANC( decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
+                       mtime_t i_dts,  mtime_t i_pts )
+{
+    if( i_data < 9 )
+        return;
+
+    const uint8_t i_did = p_data[0];
+    const uint8_t i_sdid = p_data[1];
+    const uint8_t i_datacount = p_data[2];
+
+    if( i_datacount > i_data )
+        return;
+
+    if( i_did == 0x61 ) /* EIA 608/708 */
+    {
+        if( i_sdid == 0x01 || /* EIA 708 */
+            i_sdid == 0x02 )  /* EIA 608 */
+        {
+            if( i_data < 12 )
+                return;
+
+            ParseCC( p_dec, &p_data[12], i_datacount - 12, p_data[11] & 0x1F, i_dts, i_pts );
+        }
+    }
+}
+
+static void ParseSMPTE436m( decoder_t *p_dec, const uint8_t *p_data, size_t i_data,
+                            mtime_t i_dts,  mtime_t i_pts )
+{
+    if( i_data < 16 )
+        return;
+
+    uint16_t i_pkt = GetWBE(p_data);
+    p_data += 2; i_data -= 2;
+
+    while( i_pkt-- > 0 )
+    {
+        if( i_data < 14 )
+            break;
+
+        const uint16_t i_samples = GetWBE(&p_data[4]);
+        const uint32_t i_payload = GetDWBE(&p_data[6]); /* MXF array data */
+        assert(GetDWBE(&p_data[10]) == 1);
+
+        if( i_payload > i_data - 14 )
+            break;
+
+        const uint8_t *p_vanc = NULL;
+        uint8_t *p_vanc_alloc = NULL;
+        size_t i_vanc = 0;
+
+        switch ( p_data[3] )
+        {
+            case 4: case 5: case 6:
+                p_vanc = &p_data[14];
+                if( i_samples <= i_payload )
+                    i_vanc = i_samples;
+                break;
+            case 7: case 8: case 9:
+                if( i_samples <= i_payload / 4 )
+                {
+                    p_vanc = p_vanc_alloc = malloc( i_payload * 3 / 4 );
+                    if( p_vanc_alloc )
+                    {
+                        /* Do 10bits VANC -> 8 bits VANC conversion for parsing */
+                        for( size_t i=0; i + 3 < i_payload; i+=4 )
+                        {
+                            /* Strip the 2 higher bits from 10 bits encoding */
+                            p_vanc_alloc[i_vanc + 0] = p_data[i + 0] << 2 |
+                                                       p_data[i + 1] >> 6;
+                            p_vanc_alloc[i_vanc + 1] = p_data[i + 1] << 4 |
+                                                       p_data[i + 2] >> 4;
+                            p_vanc_alloc[i_vanc + 2] = p_data[i + 2] << 6 |
+                                                       p_data[i + 3] >> 2;
+                            i_vanc += 3;
+                        }
+                        assert(i_vanc <= i_samples);
+                    }
+                }
+                break;
+            default:
+                /* Unsupported coding */
+                break;
+        }
+
+        if( p_vanc )
+        {
+            ParseVANC( p_dec, p_vanc, i_vanc, i_dts, i_pts );
+            free( p_vanc_alloc );
+        }
+
+        p_data += 14 + i_payload;
+        i_data -= 14 + i_payload;
+    }
+}
+
+static int Decode( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block )
+    {
+        ParseSMPTE436m( p_dec, p_block->p_buffer, p_block->i_buffer,
+                        p_block->i_dts, p_block->i_pts );
+        block_Release( p_block );
+    }
+
+    return VLCDEC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_t     *p_dec = (decoder_t*)p_this;
+
+    if( p_dec->fmt_in.i_cat != DATA_ES ||
+        p_dec->fmt_in.i_codec != VLC_FOURCC('s', '4', '3', '6') )
+        return VLC_EGENERIC;
+
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = NULL;
+
+    return VLC_SUCCESS;
+}
+
+static void Close( vlc_object_t *p_this )
+{
+    VLC_UNUSED(p_this);
+}
-- 
2.9.5



More information about the vlc-devel mailing list