[vlc-commits] codec: flac: support non std channel mapping (fix #15005)

Francois Cartegnie git at videolan.org
Wed Mar 1 17:32:29 CET 2017


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Mar  1 13:22:27 2017 +0100| [705a3603daf2814c9c2cd57933fc42daaa02091d] | committer: Francois Cartegnie

codec: flac: support non std channel mapping (fix #15005)

Assuming the demuxer sends the required extradata (mkv does)

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

 modules/codec/flac.c | 139 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 117 insertions(+), 22 deletions(-)

diff --git a/modules/codec/flac.c b/modules/codec/flac.c
index 96adace..661e5d6 100644
--- a/modules/codec/flac.c
+++ b/modules/codec/flac.c
@@ -36,6 +36,8 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_codec.h>
+#include <vlc_codecs.h>
+#include <vlc_aout.h>
 
 #ifdef _WIN32
 # define FLAC__NO_DLL
@@ -109,6 +111,35 @@ static const uint8_t ppi_reorder[1+FLAC_MAX_CHANNELS][FLAC_MAX_CHANNELS] =
     { 0, 1, 6, 7, 4, 5, 2, 3 },
 };
 
+/* Flac uses same order as waveformatex */
+#define MAPPED_WFX_CHANNELS 9
+static const uint32_t wfx_remapping[MAPPED_WFX_CHANNELS][2] =
+{
+    { WAVE_SPEAKER_FRONT_LEFT,              AOUT_CHAN_LEFT },
+    { WAVE_SPEAKER_FRONT_RIGHT,             AOUT_CHAN_RIGHT },
+    { WAVE_SPEAKER_FRONT_CENTER,            AOUT_CHAN_CENTER },
+    { WAVE_SPEAKER_LOW_FREQUENCY,           AOUT_CHAN_LFE },
+    { WAVE_SPEAKER_BACK_LEFT,               AOUT_CHAN_REARLEFT },
+    { WAVE_SPEAKER_BACK_RIGHT,              AOUT_CHAN_REARRIGHT },
+    { WAVE_SPEAKER_BACK_CENTER,             AOUT_CHAN_REARCENTER },
+    { WAVE_SPEAKER_SIDE_LEFT,               AOUT_CHAN_MIDDLELEFT },
+    { WAVE_SPEAKER_SIDE_RIGHT,              AOUT_CHAN_MIDDLERIGHT },
+};
+
+static const uint32_t wfx_chans_order[MAPPED_WFX_CHANNELS + 1] =
+{
+    AOUT_CHAN_LEFT,
+    AOUT_CHAN_RIGHT,
+    AOUT_CHAN_CENTER,
+    AOUT_CHAN_LFE,
+    AOUT_CHAN_REARLEFT,
+    AOUT_CHAN_REARRIGHT,
+    AOUT_CHAN_REARCENTER,
+    AOUT_CHAN_MIDDLELEFT,
+    AOUT_CHAN_MIDDLERIGHT,
+    0
+};
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -244,31 +275,91 @@ static void DecoderMetadataCallback( const FLAC__StreamDecoder *decoder,
     decoder_t *p_dec = (decoder_t *)client_data;
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    /* Setup the format */
-    p_dec->fmt_out.audio.i_rate     = metadata->data.stream_info.sample_rate;
-    p_dec->fmt_out.audio.i_channels = metadata->data.stream_info.channels;
-    if( metadata->data.stream_info.channels < 9 )
+    switch(metadata->type)
     {
-        p_dec->fmt_out.audio.i_physical_channels =
-        p_dec->fmt_out.audio.i_original_channels =
-            pi_channels_maps[metadata->data.stream_info.channels];
-        memcpy( p_sys->rgi_channels_reorder,
-                ppi_reorder[metadata->data.stream_info.channels],
-                metadata->data.stream_info.channels );
-    }
-    if (!p_dec->fmt_out.audio.i_bitspersample)
-        p_dec->fmt_out.audio.i_bitspersample =
-            metadata->data.stream_info.bits_per_sample;
-
-    msg_Dbg( p_dec, "channels:%d samplerate:%d bitspersamples:%d",
-             p_dec->fmt_out.audio.i_channels, p_dec->fmt_out.audio.i_rate,
-             p_dec->fmt_out.audio.i_bitspersample );
+        case FLAC__METADATA_TYPE_STREAMINFO:
+            /* Setup the format */
+            p_dec->fmt_out.audio.i_rate     = metadata->data.stream_info.sample_rate;
+            p_dec->fmt_out.audio.i_channels = metadata->data.stream_info.channels;
+            if( metadata->data.stream_info.channels < 9 )
+            {
+                p_dec->fmt_out.audio.i_physical_channels =
+                p_dec->fmt_out.audio.i_original_channels =
+                    pi_channels_maps[metadata->data.stream_info.channels];
+                memcpy( p_sys->rgi_channels_reorder,
+                        ppi_reorder[metadata->data.stream_info.channels],
+                        metadata->data.stream_info.channels );
+            }
+            if (!p_dec->fmt_out.audio.i_bitspersample)
+                p_dec->fmt_out.audio.i_bitspersample =
+                    metadata->data.stream_info.bits_per_sample;
+
+            msg_Dbg( p_dec, "channels:%d samplerate:%d bitspersamples:%d",
+                     p_dec->fmt_out.audio.i_channels, p_dec->fmt_out.audio.i_rate,
+                     p_dec->fmt_out.audio.i_bitspersample );
+
+            p_sys->b_stream_info = true;
+            p_sys->stream_info = metadata->data.stream_info;
+
+            date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
+            date_Set( &p_sys->end_date, VLC_TS_INVALID );
+            break;
 
-    p_sys->b_stream_info = true;
-    p_sys->stream_info = metadata->data.stream_info;
+        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+            for( FLAC__uint32 i=0; i<metadata->data.vorbis_comment.num_comments; i++ )
+            {
+                const FLAC__StreamMetadata_VorbisComment_Entry *comment =
+                        &metadata->data.vorbis_comment.comments[i];
+                /* Check for custom WAVEFORMATEX channel ordering */
+                if( comment->length > 34 &&
+                    !strncmp( "WAVEFORMATEXTENSIBLE_CHANNEL_MASK=", (char *) comment->entry, 34 ) )
+                {
+                    char *endptr = (char *) &comment->entry[34] + comment->length;
+                    const uint32_t i_wfxmask = strtoul( (char *) &comment->entry[34], &endptr, 16 );
+                    const unsigned i_wfxchannels = popcount( i_wfxmask );
+                    if( i_wfxchannels > 0 && i_wfxchannels <= AOUT_CHAN_MAX )
+                    {
+                        /* Create the vlc bitmap from wfx channels */
+                        uint32_t i_vlcmask = 0;
+                        for( uint32_t i_chan = 1; i_chan && i_chan <= i_wfxmask; i_chan <<= 1 )
+                        {
+                            if( (i_chan & i_wfxmask) == 0 )
+                                continue;
+                            for( size_t i=0; i<MAPPED_WFX_CHANNELS; i++ )
+                            {
+                                if( wfx_remapping[i][0] == i_chan )
+                                    i_vlcmask |= wfx_remapping[i][1];
+                            }
+                        }
+                        /* Check if we have the 1 to 1 mapping */
+                        if( popcount(i_vlcmask) != i_wfxchannels )
+                        {
+                            msg_Warn( p_dec, "Unsupported channel mask %x", i_wfxmask );
+                            return;
+                        }
+
+                        /* Compute the remapping */
+                        uint8_t neworder[AOUT_CHAN_MAX] = {0};
+                        aout_CheckChannelReorder( wfx_chans_order, NULL,
+                                                  i_vlcmask, neworder );
+
+                        /* /!\ Invert our source/dest reordering,
+                         * as Interleave() here works source indexes */
+                        for( unsigned i=0; i<i_wfxchannels; i++ )
+                            p_sys->rgi_channels_reorder[neworder[i]] = i;
+
+                        p_dec->fmt_out.audio.i_physical_channels =
+                        p_dec->fmt_out.audio.i_original_channels = i_vlcmask;
+                        p_dec->fmt_out.audio.i_channels = i_wfxchannels;
+                    }
+
+                    break;
+                }
+            }
 
-    date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
-    date_Set( &p_sys->end_date, VLC_TS_INVALID );
+        default:
+            break;
+    }
 }
 
 /*****************************************************************************
@@ -335,6 +426,10 @@ static int OpenDecoder( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
+    /* Enable STREAMINFO + COMMENTS */
+    FLAC__stream_decoder_set_metadata_respond( p_sys->p_flac,
+                                               FLAC__METADATA_TYPE_VORBIS_COMMENT );
+
 #ifdef USE_NEW_FLAC_API
     if( FLAC__stream_decoder_init_stream( p_sys->p_flac,
                                           DecoderReadCallback,



More information about the vlc-commits mailing list