[vlc-commits] converter/tospdif: add TRUEHD/MLP support

Thomas Guillem git at videolan.org
Wed Oct 5 18:19:04 CEST 2016


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Oct  5 15:41:01 2016 +0200| [636476b3e2d9143ee7dc0f8f00ac3794077fbff6] | committer: Thomas Guillem

converter/tospdif: add TRUEHD/MLP support

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=636476b3e2d9143ee7dc0f8f00ac3794077fbff6
---

 modules/audio_filter/converter/tospdif.c | 94 +++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/modules/audio_filter/converter/tospdif.c b/modules/audio_filter/converter/tospdif.c
index 04bc584..f1e827d 100644
--- a/modules/audio_filter/converter/tospdif.c
+++ b/modules/audio_filter/converter/tospdif.c
@@ -61,6 +61,10 @@ struct filter_sys_t
         {
             unsigned int i_nb_blocks_substream0;
         } eac3;
+        struct
+        {
+            unsigned int i_frame_count;
+        } truehd;
     } spec;
 };
 
@@ -68,6 +72,7 @@ struct filter_sys_t
 
 #define IEC61937_AC3 0x01
 #define IEC61937_EAC3 0x15
+#define IEC61937_TRUEHD 0x16
 #define IEC61937_DTS1 0x0B
 #define IEC61937_DTS2 0x0C
 #define IEC61937_DTS3 0x0D
@@ -82,6 +87,8 @@ static bool is_big_endian( filter_t *p_filter, block_t *p_in_buf )
     {
         case VLC_CODEC_A52:
         case VLC_CODEC_EAC3:
+        case VLC_CODEC_MLP:
+        case VLC_CODEC_TRUEHD:
             return true;
         case VLC_CODEC_DTS:
             return p_in_buf->p_buffer[0] == 0x1F
@@ -251,6 +258,85 @@ static int write_buffer_eac3( filter_t *p_filter, block_t *p_in_buf )
 
 }
 
+/* Adapted from libavformat/spdifenc.c:
+ * It seems Dolby TrueHD frames have to be encapsulated in MAT frames before
+ * they can be encapsulated in IEC 61937.
+ * Here we encapsulate 24 TrueHD frames in a single MAT frame, padding them
+ * to achieve constant rate.
+ * The actual format of a MAT frame is unknown, but the below seems to work.
+ * However, it seems it is not actually necessary for the 24 TrueHD frames to
+ * be in an exact alignment with the MAT frame
+ */
+static int write_buffer_truehd( filter_t *p_filter, block_t *p_in_buf )
+{
+#define TRUEHD_FRAME_OFFSET     2560
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if( !p_sys->p_out_buf
+     && write_init( p_filter, p_in_buf, 61440, 61440 / 16 ) )
+        return SPDIF_ERROR;
+
+    int i_padding = 0;
+    if( p_sys->spec.truehd.i_frame_count == 0 )
+    {
+        static const char p_mat_start_code[20] = {
+            0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00,
+            0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0
+        };
+        write_data( p_filter, p_mat_start_code, 20, true );
+        /* We need to include the S/PDIF header in the first MAT frame */
+        i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 20
+                  - SPDIF_HEADER_SIZE;
+    }
+    else if( p_sys->spec.truehd.i_frame_count == 11 )
+    {
+        /* The middle mat code need to be at the ((2560 * 12) - 4) offset */
+        i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 4;
+    }
+    else if( p_sys->spec.truehd.i_frame_count == 12 )
+    {
+        static const char p_mat_middle_code[12] = {
+            0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA,
+            0x82, 0x83, 0x49, 0x80, 0x77, 0xE0
+        };
+        write_data( p_filter, p_mat_middle_code, 12, true );
+        i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - ( 12 - 4 );
+    }
+    else if( p_sys->spec.truehd.i_frame_count == 23 )
+    {
+        static const char p_mat_end_code[16] = {
+            0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11
+        };
+
+        /* The end mat code need to be at the ((2560 * 24) - 24) offset */
+        i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer - 24;
+
+        if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
+            p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
+            return SPDIF_ERROR;
+
+        write_buffer( p_filter, p_in_buf );
+        write_padding( p_filter, i_padding );
+        write_data( p_filter, p_mat_end_code, 16, true );
+        write_finalize( p_filter, IEC61937_TRUEHD, 1 /* in bytes */ );
+        p_sys->spec.truehd.i_frame_count = 0;
+        return SPDIF_SUCCESS;
+    }
+    else
+        i_padding = TRUEHD_FRAME_OFFSET - p_in_buf->i_buffer;
+
+    if( i_padding < 0 || p_in_buf->i_buffer + i_padding >
+        p_sys->p_out_buf->i_buffer - p_sys->i_out_offset )
+        return SPDIF_ERROR;
+
+    write_buffer( p_filter, p_in_buf );
+    write_padding( p_filter, i_padding );
+    p_sys->spec.truehd.i_frame_count++;
+    return SPDIF_MORE_DATA;
+}
+
 static int write_buffer_dts( filter_t *p_filter, block_t *p_in_buf )
 {
     uint16_t i_data_type;
@@ -306,6 +392,10 @@ static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
         case VLC_CODEC_EAC3:
             i_ret = write_buffer_eac3( p_filter, p_in_buf );
             break;
+        case VLC_CODEC_MLP:
+        case VLC_CODEC_TRUEHD:
+            i_ret = write_buffer_truehd( p_filter, p_in_buf );
+            break;
         case VLC_CODEC_DTS:
             i_ret = write_buffer_dts( p_filter, p_in_buf );
             break;
@@ -342,7 +432,9 @@ static int Open( vlc_object_t *p_this )
 
     if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
           p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 &&
-          p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 ) ||
+          p_filter->fmt_in.audio.i_format != VLC_CODEC_EAC3 &&
+          p_filter->fmt_in.audio.i_format != VLC_CODEC_MLP &&
+          p_filter->fmt_in.audio.i_format != VLC_CODEC_TRUEHD ) ||
         ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL &&
           p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) )
         return VLC_EGENERIC;



More information about the vlc-commits mailing list