[vlc-devel] [PATCH 8/9] converter: spdif: improve header parser
Thomas Guillem
thomas at gllm.fr
Thu Sep 1 10:54:15 CEST 2016
In function of the codec (like EAC3 in a future commit), we may have to gather
a certain numbers of blocks.
The new parser function returns i_out_size_padded since the size of a S/PDIF
block is not necessarily nb_samples * 4. It also returns i_length_mul since the
length in the S/PDIF header can be in bits or in bytes in function of the
codec.
TODO: check if we can gather more than one frame in a block to avoid extra
padding to 0.
---
modules/audio_filter/converter/tospdif.c | 198 ++++++++++++++++++++++++-------
1 file changed, 155 insertions(+), 43 deletions(-)
diff --git a/modules/audio_filter/converter/tospdif.c b/modules/audio_filter/converter/tospdif.c
index 185f555..da34a81 100644
--- a/modules/audio_filter/converter/tospdif.c
+++ b/modules/audio_filter/converter/tospdif.c
@@ -37,47 +37,90 @@
#include <vlc_aout.h>
#include <vlc_filter.h>
-static int Create( vlc_object_t * );
+static int Open( vlc_object_t * );
+static void Close( vlc_object_t * );
vlc_module_begin ()
set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_MISC )
set_description( N_("Audio filter for A/52/DTS->S/PDIF encapsulation") )
set_capability( "audio converter", 10 )
- set_callbacks( Create, NULL )
+ set_callbacks( Open, Close )
vlc_module_end ()
-static uint16_t get_data_type( filter_t *p_filter, block_t *p_in )
+struct filter_sys_t
{
+ block_t *p_first;
+ block_t **pp_last;
+ unsigned i_total_samples;
+};
+
#define IEC61937_AC3 0x01
#define IEC61937_DTS1 0x0B
#define IEC61937_DTS2 0x0C
#define IEC61937_DTS3 0x0D
+#define SPDIF_MORE_DATA 1
+#define SPDIF_SUCCESS VLC_SUCCESS
+#define SPDIF_ERROR VLC_EGENERIC
+struct hdr_res
+{
+ uint16_t i_data_type;
+ size_t i_out_size_padded;
+ size_t i_length_mul;
+};
+
+static int parse_header_ac3( filter_t *p_filter, block_t *p_in,
+ struct hdr_res *p_res )
+{
+ (void) p_filter;
+
+ if( unlikely( p_in->i_buffer < 6 || p_in->i_nb_samples != A52_FRAME_NB ) )
+ return SPDIF_ERROR;
+ p_res->i_length_mul = 8; /* in bits */
+ p_res->i_out_size_padded = A52_FRAME_NB * 4;
+ p_res->i_data_type = ( (p_in->p_buffer[5] & 0x7) << 8 ) /* bsmod */
+ | IEC61937_AC3;
+ return SPDIF_SUCCESS;
+}
+
+static int parse_header_dts( filter_t *p_filter, block_t *p_in,
+ struct hdr_res *p_res )
+{
+ if( unlikely( p_in->i_buffer < 1 ) )
+ return SPDIF_ERROR;
+ p_res->i_out_size_padded = p_in->i_nb_samples * 4;
+ p_res->i_length_mul = 8; /* in bits */
+ switch( p_in->i_nb_samples )
+ {
+ case 512:
+ p_res->i_data_type = IEC61937_DTS1;
+ return SPDIF_SUCCESS;
+ case 1024:
+ p_res->i_data_type = IEC61937_DTS2;
+ return SPDIF_SUCCESS;
+ case 2048:
+ p_res->i_data_type = IEC61937_DTS3;
+ return SPDIF_SUCCESS;
+ default:
+ msg_Err( p_filter, "Frame size %d not supported",
+ p_in->i_nb_samples );
+ return SPDIF_ERROR;
+ }
+}
+
+static int parse_header( filter_t *p_filter, block_t *p_in,
+ struct hdr_res *p_res )
+{
switch( p_filter->fmt_in.audio.i_format )
{
case VLC_CODEC_A52:
- if( unlikely( p_in->i_buffer < 6
- || p_in->i_nb_samples != A52_FRAME_NB ) )
- return 0;
- return ( (p_in->p_buffer[5] & 0x7) << 8 ) /* bsmod */ | IEC61937_AC3;
+ return parse_header_ac3( p_filter, p_in, p_res );
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;
- }
+ return parse_header_dts( p_filter, p_in, p_res );
default:
vlc_assert_unreachable();
}
- return 0;
}
static bool is_big_endian( filter_t *p_filter, block_t *p_in )
@@ -91,21 +134,73 @@ static bool is_big_endian( filter_t *p_filter, block_t *p_in )
default:
vlc_assert_unreachable();
}
- return 0;
+}
+
+static void Flush( filter_t *p_filter )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if( p_sys->p_first != NULL )
+ {
+ block_ChainRelease( p_sys->p_first );
+ p_sys->p_first = NULL;
+ p_sys->pp_last = &p_sys->p_first;
+ p_sys->i_total_samples = 0;
+ }
}
static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
{
- size_t i_length = p_in_buf->i_buffer;
- uint8_t * p_in = p_in_buf->p_buffer;
+ filter_sys_t *p_sys = p_filter->p_sys;
+ unsigned i_nb_samples;
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;
+ struct hdr_res res;
+ int i_ret = parse_header( p_filter, p_in_buf, &res );
+ switch( i_ret )
+ {
+ case SPDIF_SUCCESS:
+ if( p_sys->p_first != NULL )
+ {
+ block_ChainLastAppend( &p_sys->pp_last, p_in_buf );
+ p_sys->i_total_samples += p_in_buf->i_nb_samples;
+ p_in_buf = block_ChainGather( p_sys->p_first );
+ if( unlikely( p_in_buf == NULL ) )
+ {
+ Flush( p_filter );
+ return NULL;
+ }
+
+ i_nb_samples = p_sys->i_total_samples;
+ p_sys->p_first = NULL;
+ p_sys->pp_last = &p_sys->p_first;
+ p_sys->i_total_samples = 0;
+ }
+ else
+ i_nb_samples = p_in_buf->i_nb_samples;
+ break;
+ case SPDIF_MORE_DATA:
+ block_ChainLastAppend( &p_sys->pp_last, p_in_buf );
+ p_sys->i_total_samples += p_in_buf->i_nb_samples;
+ return NULL;
+ case SPDIF_ERROR:
+ Flush( p_filter );
+ goto out;
+ }
+ assert( res.i_data_type > 0 );
+ assert( res.i_out_size_padded > 0 );
+ assert( res.i_length_mul == 1 || res.i_length_mul == 8 );
- size_t i_out_length = p_in_buf->i_nb_samples * 4;
- p_out_buf = block_Alloc( i_out_length );
+ size_t i_out_size = p_in_buf->i_buffer;
+ uint8_t *p_in = p_in_buf->p_buffer;
+
+ if( i_out_size > res.i_out_size_padded )
+ {
+ msg_Warn( p_filter, "buffer too big for a S/PDIF frame" );
+ return NULL;
+ }
+
+ p_out_buf = block_Alloc( res.i_out_size_padded );
if( !p_out_buf )
goto out;
uint8_t *p_out = p_out_buf->p_buffer;
@@ -117,8 +212,8 @@ static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
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 */
+ write16( &p_out[4], res.i_data_type ); /* data type */
+ write16( &p_out[6], i_out_size * res.i_length_mul ); /* length in bits or bytes */
bool b_input_big_endian = is_big_endian( p_filter, p_in_buf );
bool b_output_big_endian =
@@ -126,33 +221,34 @@ static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
if( b_input_big_endian != b_output_big_endian )
{
- swab( p_in, p_out + 8, i_length & ~1 );
+ swab( p_in, p_out + 8, i_out_size & ~1 );
- /* If i_length is odd, we have to adjust swapping a bit... */
- if( i_length & 1 && ( i_length + 9 ) <= i_out_length )
+ /* If i_out_size is odd, we have to adjust swapping a bit... */
+ if( i_out_size & 1 && ( i_out_size + 9 ) <= res.i_out_size_padded )
{
- p_out[8 + i_length - 1] = 0;
- p_out[8 + i_length] = p_in[i_length-1];
- i_length++;
+ p_out[8 + i_out_size - 1] = 0;
+ p_out[8 + i_out_size] = p_in[i_out_size-1];
+ i_out_size++;
}
} else
- memcpy( p_out + 8, p_in, i_length );
+ memcpy( p_out + 8, p_in, i_out_size );
- if( 8 + i_length < i_out_length ) /* padding */
- memset( p_out + 8 + i_length, 0, i_out_length - i_length - 8 );
+ if( 8 + i_out_size < res.i_out_size_padded ) /* padding */
+ memset( p_out + 8 + i_out_size, 0, res.i_out_size_padded - i_out_size - 8 );
p_out_buf->i_dts = p_in_buf->i_dts;
p_out_buf->i_pts = p_in_buf->i_pts;
- p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
- p_out_buf->i_buffer = i_out_length;
+ p_out_buf->i_nb_samples = i_nb_samples;
+ p_out_buf->i_buffer = res.i_out_size_padded;
out:
block_Release( p_in_buf );
return p_out_buf;
}
-static int Create( vlc_object_t *p_this )
+static int Open( vlc_object_t *p_this )
{
- filter_t * p_filter = (filter_t *)p_this;
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys;
if( ( p_filter->fmt_in.audio.i_format != VLC_CODEC_DTS &&
p_filter->fmt_in.audio.i_format != VLC_CODEC_A52 ) ||
@@ -160,7 +256,23 @@ static int Create( vlc_object_t *p_this )
p_filter->fmt_out.audio.i_format != VLC_CODEC_SPDIFB ) )
return VLC_EGENERIC;
+ p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
+ if( unlikely( p_sys == NULL ) )
+ return VLC_ENOMEM;
+ p_sys->p_first = NULL;
+ p_sys->pp_last = &p_sys->p_first;
+ p_sys->i_total_samples = 0;
+
p_filter->pf_audio_filter = DoWork;
+ p_filter->pf_flush = Flush;
return VLC_SUCCESS;
}
+
+static void Close( vlc_object_t *p_this )
+{
+ filter_t *p_filter = (filter_t *)p_this;
+
+ Flush( p_filter );
+ free( p_filter->p_sys );
+}
--
2.9.3
More information about the vlc-devel
mailing list