[vlc-commits] converter: spdif: improve header parser
Thomas Guillem
git at videolan.org
Mon Sep 12 15:16:15 CEST 2016
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Aug 31 11:21:38 2016 +0200| [08aaaa6d7385e337b8a9099b74503f46bcc0198c] | committer: Thomas Guillem
converter: spdif: improve header parser
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.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=08aaaa6d7385e337b8a9099b74503f46bcc0198c
---
modules/audio_filter/converter/tospdif.c | 230 ++++++++++++++++++++++++-------
1 file changed, 177 insertions(+), 53 deletions(-)
diff --git a/modules/audio_filter/converter/tospdif.c b/modules/audio_filter/converter/tospdif.c
index 185f555..92c5ca3 100644
--- a/modules/audio_filter/converter/tospdif.c
+++ b/modules/audio_filter/converter/tospdif.c
@@ -37,47 +37,89 @@
#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_chain_first;
+ block_t **pp_chain_last;
+};
+
#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,23 +133,45 @@ static bool is_big_endian( filter_t *p_filter, block_t *p_in )
default:
vlc_assert_unreachable();
}
- return 0;
}
-static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
+static void Flush( filter_t *p_filter )
{
- size_t i_length = p_in_buf->i_buffer;
- uint8_t * p_in = p_in_buf->p_buffer;
- block_t *p_out_buf = NULL;
+ filter_sys_t *p_sys = p_filter->p_sys;
- 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;
+ if( p_sys->p_chain_first != NULL )
+ {
+ block_ChainRelease( p_sys->p_chain_first );
+ p_sys->p_chain_first = NULL;
+ p_sys->pp_chain_last = &p_sys->p_chain_first;
+ }
+}
+
+static block_t *fill_output_buffer( filter_t *p_filter, struct hdr_res *p_res )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ unsigned i_nb_samples = 0;
+ size_t i_out_size = 0;
+ block_t *p_list = p_sys->p_chain_first;
+
+ assert( p_list != NULL );
+
+ while( p_list )
+ {
+ i_out_size += p_list->i_buffer;
+ i_nb_samples += p_list->i_nb_samples;
+ p_list = p_list->p_next;
+ }
- size_t i_out_length = p_in_buf->i_nb_samples * 4;
- p_out_buf = block_Alloc( i_out_length );
- if( !p_out_buf )
- goto out;
+ if( i_out_size + 8 > p_res->i_out_size_padded )
+ {
+ msg_Warn( p_filter, "buffer too big for a S/PDIF frame" );
+ return NULL;
+ }
+
+ block_t *p_out_buf = block_Alloc( p_res->i_out_size_padded );
+ if( unlikely(!p_out_buf) )
+ return NULL;
uint8_t *p_out = p_out_buf->p_buffer;
/* Copy the S/PDIF headers. */
@@ -117,42 +181,87 @@ 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], p_res->i_data_type ); /* data type */
+ write16( &p_out[6], i_out_size * p_res->i_length_mul ); /* length in bits or bytes */
- bool b_input_big_endian = is_big_endian( p_filter, p_in_buf );
+ p_list = p_sys->p_chain_first;
+ bool b_input_big_endian = is_big_endian( p_filter, p_list );
bool b_output_big_endian =
p_filter->fmt_out.audio.i_format == VLC_CODEC_SPDIFB;
- if( b_input_big_endian != b_output_big_endian )
+ p_out += 8;
+ while( p_list )
{
- swab( p_in, p_out + 8, i_length & ~1 );
+ uint8_t *p_in = p_list->p_buffer;
+ size_t i_in_size = p_list->i_buffer;
- /* If i_length is odd, we have to adjust swapping a bit... */
- if( i_length & 1 && ( i_length + 9 ) <= i_out_length )
+ if( b_input_big_endian != b_output_big_endian )
+ {
+ swab( p_in, p_out, i_in_size & ~1 );
+
+ if( i_in_size & 1 && ( i_out_size + 9 ) <= p_res->i_out_size_padded )
+ {
+ p_out[i_in_size - 1] = 0;
+ p_out[i_in_size] = p_in[i_in_size - 1];
+ i_out_size++;
+ p_out++;
+ }
+ p_out += i_in_size;
+ } else
{
- p_out[8 + i_length - 1] = 0;
- p_out[8 + i_length] = p_in[i_length-1];
- i_length++;
+ memcpy( p_out, p_in, i_in_size );
+ p_out += i_in_size;
}
- } else
- memcpy( p_out + 8, p_in, i_length );
+ p_list = p_list->p_next;
+ }
+
+ if( 8 + i_out_size < p_res->i_out_size_padded ) /* padding */
+ memset( p_out, 0, p_res->i_out_size_padded - i_out_size - 8 );
+
+ p_out_buf->i_dts = p_sys->p_chain_first->i_dts;
+ p_out_buf->i_pts = p_sys->p_chain_first->i_pts;
+ p_out_buf->i_nb_samples = i_nb_samples;
+ p_out_buf->i_buffer = p_res->i_out_size_padded;
- if( 8 + i_length < i_out_length ) /* padding */
- memset( p_out + 8 + i_length, 0, i_out_length - i_length - 8 );
+ return p_out_buf;
+}
- 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;
+static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ block_t *p_out_buf = NULL;
+
+ struct hdr_res res;
+ int i_ret = parse_header( p_filter, p_in_buf, &res );
+ switch( i_ret )
+ {
+ case SPDIF_SUCCESS:
+ block_ChainLastAppend( &p_sys->pp_chain_last, p_in_buf );
+ break;
+ case SPDIF_MORE_DATA:
+ block_ChainLastAppend( &p_sys->pp_chain_last, p_in_buf );
+ 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 );
+
+ p_out_buf = fill_output_buffer( p_filter, &res );
out:
- block_Release( p_in_buf );
+ block_ChainRelease( p_sys->p_chain_first );
+ p_sys->p_chain_first = NULL;
+ p_sys->pp_chain_last = &p_sys->p_chain_first;
+
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 +269,22 @@ 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_chain_first = NULL;
+ p_sys->pp_chain_last = &p_sys->p_chain_first;
+
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 );
+}
More information about the vlc-commits
mailing list