Commit f305d59a authored by Denis Charmet's avatar Denis Charmet

Support multichannel raw audio in MKV

Fix #9866
parent fdd456ea
......@@ -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 );
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" ) ||
......
......@@ -622,8 +622,12 @@ 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 != VIDEO_ES )
{
if ( tk->fmt.i_cat == NAV_ES )
{
// TODO handle the start/stop times of this packet
......@@ -631,13 +635,19 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
block_Release( p_block );
return;
}
// correct timestamping when B frames are used
if( tk->fmt.i_cat != VIDEO_ES )
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;
......
......@@ -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;
......
......@@ -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 );
......
/*****************************************************************************
* windows_audio_common.h: Windows Audio common code
*****************************************************************************
* Copyright (C) 2001-2013 VideoLAN
* $Id$
*
* Authors: Denis Charmet <typx@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*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment