vlc | branch: master | Rafaël Carré <[email protected]> | Mon Jun 13 16:01:38 2016 +0200| [57be85206cfceb1f1b79be099d03c1d99f8e0d8b] | committer: Thomas Guillem
a52tospdif: add DTS support Modified-By: Thomas Guillem <[email protected]> Signed-off-by: Thomas Guillem <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=57be85206cfceb1f1b79be099d03c1d99f8e0d8b --- modules/audio_filter/converter/a52tospdif.c | 127 ++++++++++++++++++++------- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/modules/audio_filter/converter/a52tospdif.c b/modules/audio_filter/converter/a52tospdif.c index 2e4a820..bd4175c 100644 --- a/modules/audio_filter/converter/a52tospdif.c +++ b/modules/audio_filter/converter/a52tospdif.c @@ -1,11 +1,14 @@ /***************************************************************************** - * a52tospdif.c : encapsulates A/52 frames into S/PDIF packets + * a52tospdif.c : encapsulates A/52 and DTS frames into S/PDIF packets ***************************************************************************** - * Copyright (C) 2002, 2006 VLC authors and VideoLAN + * Copyright (C) 2002, 2006-2016 VLC authors and VideoLAN * $Id$ * * Authors: Christophe Massiot <[email protected]> * Stéphane Borel <[email protected]> + * Rémi Denis-Courmont + * Rafaël Carré + * Thomas Guillem * * 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 @@ -30,6 +33,8 @@ # include "config.h" #endif +#include <assert.h> + #include <vlc_common.h> #include <vlc_plugin.h> @@ -48,7 +53,7 @@ static block_t *DoWork( filter_t *, block_t * ); vlc_module_begin () set_category( CAT_AUDIO ) set_subcategory( SUBCAT_AUDIO_MISC ) - set_description( N_("Audio filter for A/52->S/PDIF encapsulation") ) + set_description( N_("Audio filter for A/52/DTS->S/PDIF encapsulation") ) set_capability( "audio converter", 10 ) set_callbacks( Create, NULL ) vlc_module_end () @@ -60,54 +65,112 @@ static int Create( vlc_object_t *p_this ) { filter_t * p_filter = (filter_t *)p_this; - if ( p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 || - ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB && - p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL ) ) - { + if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS && + p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 ) || + ( p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFL && + p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) ) return VLC_EGENERIC; - } p_filter->pf_audio_filter = DoWork; return VLC_SUCCESS; } + +static uint16_t get_data_type( filter_t *p_filter, block_t *p_in ) +{ +#define IEC61937_AC3 0x01 +#define IEC61937_DTS1 0x0B +#define IEC61937_DTS2 0x0C +#define IEC61937_DTS3 0x0D + + switch( p_filter->fmt_in.audio.i_format ) + { + case VLC_CODEC_A52: + if( unlikely( p_in->i_buffer < 6 ) ) + return 0; + return ( (p_in->p_buffer[5] & 0x7) << 8 ) /* bsmod */ | IEC61937_AC3; + case VLC_CODEC_DTS: + if( unlikely( p_in->i_buffer < 1 ) ) + return 0; + switch( p_in->i_nb_samples ) + { + case 512: return IEC61937_DTS1; + case 1024: return IEC61937_DTS2; + case 2048: return IEC61937_DTS3; + default: + msg_Err( p_filter, "Frame size %d not supported", + p_in->i_nb_samples ); + return 0; + } + default: + vlc_assert_unreachable(); + } + return 0; +} + +static bool is_big_endian( filter_t *p_filter, block_t *p_in ) +{ + switch( p_filter->fmt_in.audio.i_format ) + { + case VLC_CODEC_A52: + return true; + case VLC_CODEC_DTS: + return p_in->p_buffer[0] == 0x1F || p_in->p_buffer[0] == 0x7F; + default: + vlc_assert_unreachable(); + } + return 0; +} + /***************************************************************************** * DoWork: convert a buffer *****************************************************************************/ static block_t *DoWork( filter_t * p_filter, block_t *p_in_buf ) { - /* AC3 is natively big endian. Most SPDIF devices have the native - * endianness of the computer system. - * On Mac OS X however, little endian devices are also common. - */ - static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 }; - static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x01 }; - uint16_t i_frame_size = p_in_buf->i_buffer / 2; + uint16_t i_length = p_in_buf->i_buffer; uint8_t * p_in = p_in_buf->p_buffer; + block_t *p_out_buf = NULL; + + uint16_t i_data_type = get_data_type( p_filter, p_in_buf ); + if( i_data_type == 0 || ( i_length + 8 ) > AOUT_SPDIF_SIZE ) + goto out; - block_t *p_out_buf = block_Alloc( AOUT_SPDIF_SIZE ); + p_out_buf = block_Alloc( AOUT_SPDIF_SIZE ); if( !p_out_buf ) goto out; - uint8_t * p_out = p_out_buf->p_buffer; + uint8_t *p_out = p_out_buf->p_buffer; /* Copy the S/PDIF headers. */ - if( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) - { - memcpy( p_out, p_sync_be, 6 ); - p_out[4] = p_in[5] & 0x7; /* bsmod */ - SetWBE( p_out + 6, i_frame_size << 4 ); - memcpy( &p_out[8], p_in, i_frame_size * 2 ); - } - else + void (*write16)(void *, uint16_t) = + ( p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB ) + ? SetWBE : SetWLE; + + write16( &p_out[0], 0xf872 ); /* syncword 1 */ + write16( &p_out[2], 0x4e1f ); /* syncword 2 */ + write16( &p_out[4], i_data_type ); /* data type */ + write16( &p_out[6], i_length * 8 ); /* length in bits */ + + bool b_input_big_endian = is_big_endian( p_filter, p_in_buf ); + bool b_output_big_endian = + p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB; + + if( b_input_big_endian != b_output_big_endian ) { - memcpy( p_out, p_sync_le, 6 ); - p_out[5] = p_in[5] & 0x7; /* bsmod */ - SetWLE( p_out + 6, i_frame_size << 4 ); - swab( p_in, &p_out[8], i_frame_size * 2 ); - } - memset( p_out + 8 + i_frame_size * 2, 0, - AOUT_SPDIF_SIZE - i_frame_size * 2 - 8 ); + swab( p_in, p_out + 8, i_length & ~1 ); + + /* If i_length is odd, we have to adjust swapping a bit... */ + if( i_length & 1 && ( i_length + 9 ) <= AOUT_SPDIF_SIZE ) + { + p_out[8 + i_length - 1] = 0; + p_out[8 + i_length] = p_in[i_length-1]; + i_length++; + } + } else + memcpy( p_out + 8, p_in, i_length ); + + if( 8 + i_length < AOUT_SPDIF_SIZE ) /* padding */ + memset( p_out + 8 + i_length, 0, AOUT_SPDIF_SIZE - i_length - 8 ); p_out_buf->i_dts = p_in_buf->i_dts; p_out_buf->i_pts = p_in_buf->i_pts; _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
