@ -30,6 +30,7 @@
# include <alsa/asoundlib.h>
# include "libavformat/avformat.h"
# include "libavutil/avassert.h"
# include "alsa-audio.h"
@ -60,6 +61,127 @@ static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id)
}
}
# define REORDER_OUT_50(NAME, TYPE) \
static void alsa_reorder_ # # NAME # # _out_50 ( const void * in_v , void * out_v , int n ) \
{ \
const TYPE * in = in_v ; \
TYPE * out = out_v ; \
\
while ( n - - > 0 ) { \
out [ 0 ] = in [ 0 ] ; \
out [ 1 ] = in [ 1 ] ; \
out [ 2 ] = in [ 3 ] ; \
out [ 3 ] = in [ 4 ] ; \
out [ 4 ] = in [ 2 ] ; \
in + = 5 ; \
out + = 5 ; \
} \
}
# define REORDER_OUT_51(NAME, TYPE) \
static void alsa_reorder_ # # NAME # # _out_51 ( const void * in_v , void * out_v , int n ) \
{ \
const TYPE * in = in_v ; \
TYPE * out = out_v ; \
\
while ( n - - > 0 ) { \
out [ 0 ] = in [ 0 ] ; \
out [ 1 ] = in [ 1 ] ; \
out [ 2 ] = in [ 4 ] ; \
out [ 3 ] = in [ 5 ] ; \
out [ 4 ] = in [ 2 ] ; \
out [ 5 ] = in [ 3 ] ; \
in + = 6 ; \
out + = 6 ; \
} \
}
# define REORDER_OUT_71(NAME, TYPE) \
static void alsa_reorder_ # # NAME # # _out_71 ( const void * in_v , void * out_v , int n ) \
{ \
const TYPE * in = in_v ; \
TYPE * out = out_v ; \
\
while ( n - - > 0 ) { \
out [ 0 ] = in [ 0 ] ; \
out [ 1 ] = in [ 1 ] ; \
out [ 2 ] = in [ 4 ] ; \
out [ 3 ] = in [ 5 ] ; \
out [ 4 ] = in [ 2 ] ; \
out [ 5 ] = in [ 3 ] ; \
out [ 6 ] = in [ 6 ] ; \
out [ 7 ] = in [ 7 ] ; \
in + = 8 ; \
out + = 8 ; \
} \
}
REORDER_OUT_50 ( int8 , int8_t )
REORDER_OUT_51 ( int8 , int8_t )
REORDER_OUT_71 ( int8 , int8_t )
REORDER_OUT_50 ( int16 , int16_t )
REORDER_OUT_51 ( int16 , int16_t )
REORDER_OUT_71 ( int16 , int16_t )
REORDER_OUT_50 ( int32 , int32_t )
REORDER_OUT_51 ( int32 , int32_t )
REORDER_OUT_71 ( int32 , int32_t )
REORDER_OUT_50 ( f32 , float )
REORDER_OUT_51 ( f32 , float )
REORDER_OUT_71 ( f32 , float )
# define FORMAT_I8 0
# define FORMAT_I16 1
# define FORMAT_I32 2
# define FORMAT_F32 3
# define PICK_REORDER(layout)\
switch ( format ) { \
case FORMAT_I8 : s - > reorder_func = alsa_reorder_int8_out_ # # layout ; break ; \
case FORMAT_I16 : s - > reorder_func = alsa_reorder_int16_out_ # # layout ; break ; \
case FORMAT_I32 : s - > reorder_func = alsa_reorder_int32_out_ # # layout ; break ; \
case FORMAT_F32 : s - > reorder_func = alsa_reorder_f32_out_ # # layout ; break ; \
}
static av_cold int find_reorder_func ( AlsaData * s , int codec_id , int64_t layout , int out )
{
int format ;
/* reordering input is not currently supported */
if ( ! out )
return AVERROR ( ENOSYS ) ;
/* reordering is not needed for QUAD or 2_2 layout */
if ( layout = = AV_CH_LAYOUT_QUAD | | layout = = AV_CH_LAYOUT_2_2 )
return 0 ;
switch ( codec_id ) {
case CODEC_ID_PCM_S8 :
case CODEC_ID_PCM_U8 :
case CODEC_ID_PCM_ALAW :
case CODEC_ID_PCM_MULAW : format = FORMAT_I8 ; break ;
case CODEC_ID_PCM_S16LE :
case CODEC_ID_PCM_S16BE :
case CODEC_ID_PCM_U16LE :
case CODEC_ID_PCM_U16BE : format = FORMAT_I16 ; break ;
case CODEC_ID_PCM_S32LE :
case CODEC_ID_PCM_S32BE :
case CODEC_ID_PCM_U32LE :
case CODEC_ID_PCM_U32BE : format = FORMAT_I32 ; break ;
case CODEC_ID_PCM_F32LE :
case CODEC_ID_PCM_F32BE : format = FORMAT_F32 ; break ;
default : return AVERROR ( ENOSYS ) ;
}
if ( layout = = AV_CH_LAYOUT_5POINT0_BACK | | layout = = AV_CH_LAYOUT_5POINT0 )
PICK_REORDER ( 50 )
else if ( layout = = AV_CH_LAYOUT_5POINT1_BACK | | layout = = AV_CH_LAYOUT_5POINT1 )
PICK_REORDER ( 51 )
else if ( layout = = AV_CH_LAYOUT_7POINT1 )
PICK_REORDER ( 71 )
return s - > reorder_func ? 0 : AVERROR ( ENOSYS ) ;
}
av_cold int ff_alsa_open ( AVFormatContext * ctx , snd_pcm_stream_t mode ,
unsigned int * sample_rate ,
int channels , enum CodecID * codec_id )
@ -71,6 +193,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
snd_pcm_t * h ;
snd_pcm_hw_params_t * hw_params ;
snd_pcm_uframes_t buffer_size , period_size ;
int64_t layout = ctx - > streams [ 0 ] - > codec - > channel_layout ;
if ( ctx - > filename [ 0 ] = = 0 ) audio_device = " default " ;
else audio_device = ctx - > filename ;
@ -163,6 +286,21 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
snd_pcm_hw_params_free ( hw_params ) ;
if ( channels > 2 & & layout ) {
if ( find_reorder_func ( s , * codec_id , layout , mode = = SND_PCM_STREAM_PLAYBACK ) < 0 ) {
char name [ 128 ] ;
av_get_channel_layout_string ( name , sizeof ( name ) , channels , layout ) ;
av_log ( ctx , AV_LOG_WARNING , " ALSA channel layout unknown or unimplemented for %s %s. \n " ,
name , mode = = SND_PCM_STREAM_PLAYBACK ? " playback " : " capture " ) ;
}
if ( s - > reorder_func ) {
s - > reorder_buf_size = buffer_size ;
s - > reorder_buf = av_malloc ( s - > reorder_buf_size * s - > frame_size ) ;
if ( ! s - > reorder_buf )
goto fail1 ;
}
}
s - > h = h ;
return 0 ;
@ -177,6 +315,7 @@ av_cold int ff_alsa_close(AVFormatContext *s1)
{
AlsaData * s = s1 - > priv_data ;
av_freep ( & s - > reorder_buf ) ;
snd_pcm_close ( s - > h ) ;
return 0 ;
}
@ -201,3 +340,19 @@ int ff_alsa_xrun_recover(AVFormatContext *s1, int err)
}
return err ;
}
int ff_alsa_extend_reorder_buf ( AlsaData * s , int min_size )
{
int size = s - > reorder_buf_size ;
void * r ;
av_assert0 ( size ! = 0 ) ;
while ( size < min_size )
size * = 2 ;
r = av_realloc ( s - > reorder_buf , size * s - > frame_size ) ;
if ( ! r )
return AVERROR ( ENOMEM ) ;
s - > reorder_buf = r ;
s - > reorder_buf_size = size ;
return 0 ;
}