[vlc-devel] [PATCH] Support multichannel raw audio in MKV
Denis Charmet
typx at dinauz.org
Sun Nov 17 15:45:07 CET 2013
Fix #9866
---
modules/demux/mkv/matroska_segment_parse.cpp | 52 +++++++++++++++++++------
modules/demux/mkv/mkv.cpp | 26 +++++++++----
modules/demux/mkv/mkv.hpp | 4 ++
modules/demux/wav.c | 38 ++++--------------
modules/demux/windows_audio_commons.h | 58 ++++++++++++++++++++++++++++
5 files changed, 128 insertions(+), 50 deletions(-)
create mode 100644 modules/demux/windows_audio_commons.h
diff --git a/modules/demux/mkv/matroska_segment_parse.cpp b/modules/demux/mkv/matroska_segment_parse.cpp
index 7b4c359..8845823 100644
--- a/modules/demux/mkv/matroska_segment_parse.cpp
+++ b/modules/demux/mkv/matroska_segment_parse.cpp
@@ -31,6 +31,7 @@
extern "C" {
#include "../vobsub.h"
#include "../xiph.h"
+#include "../windows_audio_commons.h"
}
#include <vlc_codecs.h>
@@ -1429,18 +1430,7 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
else
{
WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_tk->p_extra_data;
- if( p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- p_tk->i_extra_data >= sizeof(WAVEFORMATEXTENSIBLE) )
- {
- WAVEFORMATEXTENSIBLE * p_wext = (WAVEFORMATEXTENSIBLE*) p_wf;
- sf_tag_to_fourcc( &p_wext->SubFormat, &p_tk->fmt.i_codec, NULL);
- /* FIXME should we use Samples and dwChannelMask?*/
- }
- else
- wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_tk->fmt.i_codec, NULL );
- if( p_tk->fmt.i_codec == VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
- msg_Err( &sys.demuxer, "Unrecognized wf tag: 0x%x", GetWLE( &p_wf->wFormatTag ) );
p_tk->fmt.audio.i_channels = GetWLE( &p_wf->nChannels );
p_tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
p_tk->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
@@ -1451,8 +1441,46 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
if( p_tk->fmt.i_extra > 0 )
{
p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
- memcpy( p_tk->fmt.p_extra, &p_wf[1], p_tk->fmt.i_extra );
+ if( p_tk->fmt.p_extra )
+ memcpy( p_tk->fmt.p_extra, &p_wf[1], p_tk->fmt.i_extra );
+ else
+ p_tk->fmt.i_extra = 0;
}
+
+ if( p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ p_tk->i_extra_data >= sizeof(WAVEFORMATEXTENSIBLE) )
+ {
+ WAVEFORMATEXTENSIBLE * p_wext = (WAVEFORMATEXTENSIBLE*) p_wf;
+ sf_tag_to_fourcc( &p_wext->SubFormat, &p_tk->fmt.i_codec, NULL);
+ /* FIXME should we use Samples */
+
+ if( p_tk->fmt.audio.i_channels > 2 &&
+ ( p_tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) ) )
+ {
+ uint32_t wfextcm = GetDWLE( &p_wext->dwChannelMask );
+ int match;
+ unsigned i_channel_mask = getChannelMask( &wfextcm,
+ p_tk->fmt.audio.i_channels,
+ &match );
+ p_tk->fmt.i_codec = vlc_fourcc_GetCodecAudio( p_tk->fmt.i_codec,
+ p_tk->fmt.audio.i_bitspersample );
+ if( i_channel_mask )
+ {
+ p_tk->i_chans_to_reorder = aout_CheckChannelReorder(
+ pi_channels_aout, NULL,
+ i_channel_mask,
+ p_tk->pi_chan_table );
+
+ p_tk->fmt.audio.i_physical_channels =
+ p_tk->fmt.audio.i_original_channels = i_channel_mask;
+ }
+ }
+ }
+ else
+ wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_tk->fmt.i_codec, NULL );
+
+ if( p_tk->fmt.i_codec == VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
+ msg_Err( &sys.demuxer, "Unrecognized wf tag: 0x%x", GetWLE( &p_wf->wFormatTag ) );
}
}
else if( !strcmp( p_tk->psz_codec, "A_MPEG/L3" ) ||
diff --git a/modules/demux/mkv/mkv.cpp b/modules/demux/mkv/mkv.cpp
index 7d42d83..42f3334 100644
--- a/modules/demux/mkv/mkv.cpp
+++ b/modules/demux/mkv/mkv.cpp
@@ -622,22 +622,32 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
p_block->i_length = -1 * i_duration * tk->fmt.audio.i_rate
/ CLOCK_FREQ;
}
+ break;
}
- if ( tk->fmt.i_cat == NAV_ES )
- {
- // TODO handle the start/stop times of this packet
- p_sys->p_ev->SetPci( (const pci_t *)&p_block->p_buffer[1]);
- block_Release( p_block );
- return;
- }
- // correct timestamping when B frames are used
+
if( tk->fmt.i_cat != VIDEO_ES )
{
+ if ( tk->fmt.i_cat == NAV_ES )
+ {
+ // TODO handle the start/stop times of this packet
+ p_sys->p_ev->SetPci( (const pci_t *)&p_block->p_buffer[1]);
+ block_Release( p_block );
+ return;
+ }
+ else if( tk->fmt.i_cat == AUDIO_ES )
+ {
+ if( tk->i_chans_to_reorder )
+ aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
+ tk->fmt.audio.i_channels,
+ tk->pi_chan_table, tk->fmt.i_codec );
+
+ }
p_block->i_dts = p_block->i_pts = i_pts;
}
else
{
+ // correct timestamping when B frames are used
if( tk->b_dts_only )
{
p_block->i_pts = VLC_TS_INVALID;
diff --git a/modules/demux/mkv/mkv.hpp b/modules/demux/mkv/mkv.hpp
index 7cae3e7..a883a46 100644
--- a/modules/demux/mkv/mkv.hpp
+++ b/modules/demux/mkv/mkv.hpp
@@ -53,6 +53,7 @@
#include <vlc_charset.h>
#include <vlc_input.h>
#include <vlc_demux.h>
+#include <vlc_aout.h> /* For reordering */
#include <iostream>
#include <cassert>
@@ -211,6 +212,9 @@ struct mkv_track_t
/* audio */
unsigned int i_original_rate;
+ uint8_t i_chans_to_reorder; /* do we need channel reordering */
+ uint8_t pi_chan_table[AOUT_CHAN_MAX];
+
/* Private track paramters */
PrivateTrackData *p_sys;
diff --git a/modules/demux/wav.c b/modules/demux/wav.c
index 258ba7a..9a1c3d5 100644
--- a/modules/demux/wav.c
+++ b/modules/demux/wav.c
@@ -35,6 +35,8 @@
#include <vlc_aout.h>
#include <vlc_codecs.h>
+#include "windows_audio_commons.h"
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
@@ -80,17 +82,6 @@ static int FrameInfo_MS_ADPCM ( unsigned int *, int *, const es_format_t * );
static int FrameInfo_PCM ( unsigned int *, int *, const es_format_t * );
static int FrameInfo_MSGSM ( unsigned int *, int *, const es_format_t * );
-static const uint32_t pi_channels_src[] =
- { WAVE_SPEAKER_FRONT_LEFT, WAVE_SPEAKER_FRONT_RIGHT,
- WAVE_SPEAKER_FRONT_CENTER, WAVE_SPEAKER_LOW_FREQUENCY,
- WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT, WAVE_SPEAKER_BACK_CENTER,
- WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
-static const uint32_t pi_channels_in[] =
- { 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 };
-
/*****************************************************************************
* Open: check file and initializes structures
*****************************************************************************/
@@ -230,20 +221,7 @@ static int Open( vlc_object_t * p_this )
if( i_channel_mask )
{
int i_match = 0;
- for( unsigned i = 0; i < sizeof(pi_channels_src)/sizeof(*pi_channels_src); i++ )
- {
- if( i_channel_mask & pi_channels_src[i] )
- {
- if( !( p_sys->i_channel_mask & pi_channels_in[i] ) )
- i_match++;
-
- i_channel_mask &= ~pi_channels_src[i];
- p_sys->i_channel_mask |= pi_channels_in[i];
-
- if( i_match >= p_sys->fmt.audio.i_channels )
- break;
- }
- }
+ p_sys->i_channel_mask = getChannelMask( &i_channel_mask, p_sys->fmt.audio.i_channels, &i_match );
if( i_channel_mask )
msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", i_channel_mask );
if( i_match < p_sys->fmt.audio.i_channels )
@@ -269,11 +247,11 @@ static int Open( vlc_object_t * p_this )
}
}
/* Well fill up with what we can */
- for( unsigned i = 0; i < sizeof(pi_channels_in)/sizeof(*pi_channels_in) && i_missing > 0; i++ )
+ for( unsigned i = 0; i < sizeof(pi_channels_aout)/sizeof(*pi_channels_aout) && i_missing > 0; i++ )
{
- if( !( p_sys->i_channel_mask & pi_channels_in[i] ) )
+ if( !( p_sys->i_channel_mask & pi_channels_aout[i] ) )
{
- p_sys->i_channel_mask |= pi_channels_in[i];
+ p_sys->i_channel_mask |= pi_channels_aout[i];
i_missing--;
if( i_missing <= 0 )
@@ -294,7 +272,7 @@ static int Open( vlc_object_t * p_this )
p_sys->fmt.audio.i_channels > 2 && p_sys->fmt.audio.i_channels <= 9 )
{
for( int i = 0; i < p_sys->fmt.audio.i_channels; i++ )
- p_sys->i_channel_mask |= pi_channels_in[i];
+ p_sys->i_channel_mask |= pi_channels_aout[i];
}
if( p_sys->i_channel_mask )
@@ -302,7 +280,7 @@ static int Open( vlc_object_t * p_this )
if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') ||
p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') )
p_sys->i_chans_to_reorder =
- aout_CheckChannelReorder( pi_channels_in, NULL,
+ aout_CheckChannelReorder( pi_channels_aout, NULL,
p_sys->i_channel_mask,
p_sys->pi_chan_table );
diff --git a/modules/demux/windows_audio_commons.h b/modules/demux/windows_audio_commons.h
new file mode 100644
index 0000000..80aa5cb
--- /dev/null
+++ b/modules/demux/windows_audio_commons.h
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * windows_audio_common.h: Windows Audio common code
+ *****************************************************************************
+ * Copyright (C) 2001-2013 VideoLAN
+ * $Id$
+ *
+ * Authors: Denis Charmet <typx at videolan.org>
+ *
+ * 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.
+ *****************************************************************************/
+#ifndef DMX_WINDOWS_AUDIO_COMMONS_H
+#define DMX_WINDOWS_AUDIO_COMMONS_H
+
+#include <vlc_aout.h>
+#include <vlc_codecs.h>
+
+static const uint32_t pi_channels_src[] = { WAVE_SPEAKER_FRONT_LEFT,
+ WAVE_SPEAKER_FRONT_RIGHT, WAVE_SPEAKER_FRONT_CENTER,
+ WAVE_SPEAKER_LOW_FREQUENCY, WAVE_SPEAKER_BACK_LEFT, WAVE_SPEAKER_BACK_RIGHT,
+ WAVE_SPEAKER_BACK_CENTER, WAVE_SPEAKER_SIDE_LEFT, WAVE_SPEAKER_SIDE_RIGHT, 0 };
+
+static const uint32_t pi_channels_aout[] = { 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 };
+
+static inline unsigned getChannelMask( uint32_t * wvfextChannelMask, int i_channels, int * i_match )
+{
+ unsigned i_channel_mask = 0;
+ *i_match = 0;
+ for( unsigned i = 0;
+ i < sizeof(pi_channels_src)/sizeof(*pi_channels_src) &&
+ *i_match < i_channels; i++ )
+ {
+ if( *wvfextChannelMask & pi_channels_src[i] )
+ {
+ if( !( i_channel_mask & pi_channels_aout[i] ) )
+ *i_match += 1;
+
+ *wvfextChannelMask &= ~pi_channels_src[i];
+ i_channel_mask |= pi_channels_aout[i];
+ }
+ }
+ return i_channel_mask;
+}
+
+#endif /*DMX_WINDOWS_AUDIO_COMMONS_H*/
--
1.8.4.rc3
More information about the vlc-devel
mailing list