@ -34,7 +34,6 @@
# include "libavutil/attributes.h"
# include "libavutil/crc.h"
# include "libavutil/fifo.h"
# include "bytestream.h"
# include "parser.h"
# include "flac.h"
@ -57,6 +56,14 @@
# define MAX_FRAME_HEADER_SIZE 16
# define MAX_FRAME_VERIFY_SIZE (MAX_FRAME_HEADER_SIZE + 1)
typedef struct FifoBuffer {
uint8_t * buffer ;
uint8_t * end ;
uint8_t * rptr ;
uint8_t * wptr ;
int empty ;
} FifoBuffer ;
typedef struct FLACHeaderMarker {
int offset ; /**< byte offset from start of FLACParseContext->buffer */
int link_penalty [ FLAC_MAX_SEQUENTIAL_HEADERS ] ; /**< array of local scores
@ -84,7 +91,7 @@ typedef struct FLACParseContext {
int nb_headers_buffered ; /**< number of headers that are buffered */
int best_header_valid ; /**< flag set when the parser returns junk;
if set return best_header next time */
AV FifoBuffer * fifo_buf ; /**< buffer to store all data until headers
FifoBuffer fifo_buf ; /**< buffer to store all data until headers
can be verified */
int end_padded ; /**< specifies if fifo_buf's end is padded */
uint8_t * wrap_buf ; /**< general fifo read buffer when wrapped */
@ -127,6 +134,18 @@ static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf,
return 1 ;
}
static size_t flac_fifo_size ( const FifoBuffer * f )
{
if ( f - > wptr < = f - > rptr & & ! f - > empty )
return ( f - > wptr - f - > buffer ) + ( f - > end - f - > rptr ) ;
return f - > wptr - f - > rptr ;
}
static size_t flac_fifo_space ( const FifoBuffer * f )
{
return f - > end - f - > buffer - flac_fifo_size ( f ) ;
}
/**
* Non - destructive fast fifo pointer fetching
* Returns a pointer from the specified offset .
@ -143,7 +162,7 @@ static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf,
static uint8_t * flac_fifo_read_wrap ( FLACParseContext * fpc , int offset , int len ,
uint8_t * * wrap_buf , int * allocated_size )
{
AV FifoBuffer * f = fpc - > fifo_buf ;
FifoBuffer * f = & fpc - > fifo_buf ;
uint8_t * start = f - > rptr + offset ;
uint8_t * tmp_buf ;
@ -180,9 +199,8 @@ static uint8_t *flac_fifo_read_wrap(FLACParseContext *fpc, int offset, int len,
* A second call to flac_fifo_read ( with new offset and len ) should be called
* to get the post - wrap buf if the returned len is less than the requested .
* */
static uint8_t * flac_fifo_read ( FLACParseContext * fpc , int offset , int * len )
static uint8_t * flac_fifo_read ( FifoBuffer * f , int offset , int * len )
{
AVFifoBuffer * f = fpc - > fifo_buf ;
uint8_t * start = f - > rptr + offset ;
if ( start > = f - > end )
@ -191,6 +209,108 @@ static uint8_t *flac_fifo_read(FLACParseContext *fpc, int offset, int *len)
return start ;
}
static int flac_fifo_grow ( FifoBuffer * f , size_t inc )
{
size_t size_old = f - > end - f - > buffer ;
size_t offset_r = f - > rptr - f - > buffer ;
size_t offset_w = f - > wptr - f - > buffer ;
size_t size_new ;
uint8_t * tmp ;
if ( size_old > SIZE_MAX - inc )
return AVERROR ( EINVAL ) ;
size_new = size_old + inc ;
tmp = av_realloc ( f - > buffer , size_new ) ;
if ( ! tmp )
return AVERROR ( ENOMEM ) ;
// move the data from the beginning of the ring buffer
// to the newly allocated space
if ( offset_w < = offset_r & & ! f - > empty ) {
const size_t copy = FFMIN ( inc , offset_w ) ;
memcpy ( tmp + size_old , tmp , copy ) ;
if ( copy < offset_w ) {
memmove ( tmp , tmp + copy , offset_w - copy ) ;
offset_w - = copy ;
} else
offset_w = size_old + copy ;
}
f - > buffer = tmp ;
f - > end = f - > buffer + size_new ;
f - > rptr = f - > buffer + offset_r ;
f - > wptr = f - > buffer + offset_w ;
return 0 ;
}
static int flac_fifo_write ( FifoBuffer * f , const uint8_t * src , size_t size )
{
uint8_t * wptr ;
if ( flac_fifo_space ( f ) < size ) {
int ret = flac_fifo_grow ( f , FFMAX ( flac_fifo_size ( f ) , size ) ) ;
if ( ret < 0 )
return ret ;
}
if ( size )
f - > empty = 0 ;
wptr = f - > wptr ;
do {
size_t len = FFMIN ( f - > end - wptr , size ) ;
memcpy ( wptr , src , len ) ;
src + = len ;
wptr + = len ;
if ( wptr > = f - > end )
wptr = f - > buffer ;
size - = len ;
} while ( size > 0 ) ;
f - > wptr = wptr ;
return 0 ;
}
static void flac_fifo_drain ( FifoBuffer * f , size_t size )
{
size_t size_cur = flac_fifo_size ( f ) ;
av_assert0 ( size_cur > = size ) ;
if ( size_cur = = size )
f - > empty = 1 ;
f - > rptr + = size ;
if ( f - > rptr > = f - > end )
f - > rptr - = f - > end - f - > buffer ;
}
static int flac_fifo_alloc ( FifoBuffer * f , size_t size )
{
memset ( f , 0 , sizeof ( * f ) ) ;
f - > buffer = av_realloc ( NULL , size ) ;
if ( ! f - > buffer )
return AVERROR ( ENOMEM ) ;
f - > wptr = f - > buffer ;
f - > rptr = f - > buffer ;
f - > end = f - > buffer + size ;
f - > empty = 1 ;
return 0 ;
}
static void flac_fifo_free ( FifoBuffer * f )
{
av_freep ( & f - > buffer ) ;
memset ( f , 0 , sizeof ( * f ) ) ;
}
static int find_headers_search_validate ( FLACParseContext * fpc , int offset )
{
FLACFrameInfo fi ;
@ -263,9 +383,9 @@ static int find_new_headers(FLACParseContext *fpc, int search_start)
fpc - > nb_headers_found = 0 ;
/* Search for a new header of at most 16 bytes. */
search_end = av_fifo_size ( fpc - > fifo_buf ) - ( MAX_FRAME_HEADER_SIZE - 1 ) ;
search_end = flac_fifo_size ( & fpc - > fifo_buf ) - ( MAX_FRAME_HEADER_SIZE - 1 ) ;
read_len = search_end - search_start + 1 ;
buf = flac_fifo_read ( fpc , search_start , & read_len ) ;
buf = flac_fifo_read ( & fpc - > fifo_buf , search_start , & read_len ) ;
size = find_headers_search ( fpc , buf , read_len , search_start ) ;
search_start + = read_len - 1 ;
@ -277,7 +397,7 @@ static int find_new_headers(FLACParseContext *fpc, int search_start)
/* search_start + 1 is the post-wrap offset in the fifo. */
read_len = search_end - ( search_start + 1 ) + 1 ;
buf = flac_fifo_read ( fpc , search_start + 1 , & read_len ) ;
buf = flac_fifo_read ( & fpc - > fifo_buf , search_start + 1 , & read_len ) ;
wrap [ 1 ] = buf [ 0 ] ;
if ( ( AV_RB16 ( wrap ) & 0xFFFE ) = = 0xFFF8 ) {
@ -406,12 +526,12 @@ static int check_header_mismatch(FLACParseContext *fpc,
}
read_len = end - > offset - start - > offset ;
buf = flac_fifo_read ( fpc , start - > offset , & read_len ) ;
buf = flac_fifo_read ( & fpc - > fifo_buf , start - > offset , & read_len ) ;
crc = av_crc ( av_crc_get_table ( AV_CRC_16_ANSI ) , 0 , buf , read_len ) ;
read_len = ( end - > offset - start - > offset ) - read_len ;
if ( read_len ) {
buf = flac_fifo_read ( fpc , end - > offset - read_len , & read_len ) ;
buf = flac_fifo_read ( & fpc - > fifo_buf , end - > offset - read_len , & read_len ) ;
crc = av_crc ( av_crc_get_table ( AV_CRC_16_ANSI ) , crc , buf , read_len ) ;
}
}
@ -500,7 +620,7 @@ static int get_best_header(FLACParseContext *fpc, const uint8_t **poutbuf,
FLACHeaderMarker * header = fpc - > best_header ;
FLACHeaderMarker * child = header - > best_child ;
if ( ! child ) {
* poutbuf_size = av_fifo_size ( fpc - > fifo_buf ) - header - > offset ;
* poutbuf_size = flac_fifo_size ( & fpc - > fifo_buf ) - header - > offset ;
} else {
* poutbuf_size = child - > offset - header - > offset ;
@ -519,7 +639,6 @@ static int get_best_header(FLACParseContext *fpc, const uint8_t **poutbuf,
& fpc - > wrap_buf ,
& fpc - > wrap_buf_allocated_size ) ;
if ( fpc - > pc - > flags & PARSER_FLAG_USE_CODEC_TS ) {
if ( header - > fi . is_var_size )
fpc - > pc - > pts = header - > fi . frame_or_sample_num ;
@ -534,7 +653,7 @@ static int get_best_header(FLACParseContext *fpc, const uint8_t **poutbuf,
/* Return the negative overread index so the client can compute pos.
This should be the amount overread to the beginning of the child */
if ( child )
return child - > offset - av_fifo_size ( fpc - > fifo_buf ) ;
return child - > offset - flac_fifo_size ( & fpc - > fifo_buf ) ;
return 0 ;
}
@ -586,7 +705,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
fpc - > nb_headers_buffered - - ;
}
/* Release returned data from ring buffer. */
av_fifo_drain ( fpc - > fifo_buf , best_child - > offset ) ;
flac_fifo_drain ( & fpc - > fifo_buf , best_child - > offset ) ;
/* Fix the offset for the headers remaining to match the new buffer. */
for ( curr = best_child - > next ; curr ; curr = curr - > next )
@ -620,7 +739,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
while ( ( buf_size & & read_end < buf + buf_size & &
fpc - > nb_headers_buffered < FLAC_MIN_HEADERS )
| | ( ! buf_size & & ! fpc - > end_padded ) ) {
int start_offset ;
int start_offset , ret ;
/* Pad the end once if EOF, to check the final region for headers. */
if ( ! buf_size ) {
@ -634,8 +753,8 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
nb_desired * FLAC_AVG_FRAME_SIZE ) ;
}
if ( ! av_fifo_space ( fpc - > fifo_buf ) & &
av_fifo_size ( fpc - > fifo_buf ) / FLAC_AVG_FRAME_SIZE >
if ( ! flac_fifo_space ( & fpc - > fifo_buf ) & &
flac_fifo_size ( & fpc - > fifo_buf ) / FLAC_AVG_FRAME_SIZE >
fpc - > nb_headers_buffered * 20 ) {
/* There is less than one valid flac header buffered for 20 headers
* buffered . Therefore the fifo is most likely filled with invalid
@ -644,24 +763,20 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
/* Fill the buffer. */
if ( av_fifo_space ( fpc - > fifo_buf ) < read_end - read_start
& & av_fifo_realloc2 ( fpc - > fifo_buf , ( read_end - read_start ) + 2 * av_fifo_size ( fpc - > fifo_buf ) ) < 0 ) {
av_log ( avctx , AV_LOG_ERROR ,
" couldn't reallocate buffer of size % " PTRDIFF_SPECIFIER " \n " ,
( read_end - read_start ) + av_fifo_size ( fpc - > fifo_buf ) ) ;
goto handle_error ;
}
if ( buf_size ) {
av_fifo_generic_write ( fpc - > fifo_buf , ( void * ) read_start ,
read_end - read_start , NULL ) ;
ret = flac_fifo_write ( & fpc - > fifo_buf , read_start ,
read_end - read_start ) ;
} else {
int8_t pad [ MAX_FRAME_HEADER_SIZE ] = { 0 } ;
av_fifo_generic_write ( fpc - > fifo_buf , pad , sizeof ( pad ) , NULL ) ;
ret = flac_fifo_write ( & fpc - > fifo_buf , pad , sizeof ( pad ) ) ;
}
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Error buffering data \n " ) ;
goto handle_error ;
}
/* Tag headers and update sequences. */
start_offset = av_fifo_size ( fpc - > fifo_buf ) -
start_offset = flac_fifo_size ( & fpc - > fifo_buf ) -
( ( read_end - read_start ) + ( MAX_FRAME_HEADER_SIZE - 1 ) ) ;
start_offset = FFMAX ( 0 , start_offset ) ;
nb_headers = find_new_headers ( fpc , start_offset ) ;
@ -689,14 +804,15 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
/* restore the state pre-padding */
if ( fpc - > end_padded ) {
int warp = fpc - > fifo_buf - > wptr - fpc - > fifo_buf - > buffer < MAX_FRAME_HEADER_SIZE ;
int empty = flac_fifo_size ( & fpc - > fifo_buf ) = = MAX_FRAME_HEADER_SIZE ;
int warp = fpc - > fifo_buf . wptr - fpc - > fifo_buf . buffer < MAX_FRAME_HEADER_SIZE ;
/* HACK: drain the tail of the fifo */
fpc - > fifo_buf - > wptr - = MAX_FRAME_HEADER_SIZE ;
fpc - > fifo_buf - > wndx - = MAX_FRAME_HEADER_SIZE ;
fpc - > fifo_buf . wptr - = MAX_FRAME_HEADER_SIZE ;
if ( warp ) {
fpc - > fifo_buf - > wptr + = fpc - > fifo_buf - > end -
fpc - > fifo_buf - > buffer ;
fpc - > fifo_buf . wptr + = fpc - > fifo_buf . end -
fpc - > fifo_buf . buffer ;
}
fpc - > fifo_buf . empty = empty ;
read_start = read_end = NULL ;
}
}
@ -727,7 +843,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
& fpc - > wrap_buf ,
& fpc - > wrap_buf_allocated_size ) ;
return buf_size ? ( read_end - buf ) : ( fpc - > best_header - > offset -
av_fifo_size ( fpc - > fifo_buf ) ) ;
flac_fifo_size ( & fpc - > fifo_buf ) ) ;
}
if ( ! buf_size )
return get_best_header ( fpc , poutbuf , poutbuf_size ) ;
@ -742,11 +858,13 @@ handle_error:
static av_cold int flac_parse_init ( AVCodecParserContext * c )
{
FLACParseContext * fpc = c - > priv_data ;
int ret ;
fpc - > pc = c ;
/* There will generally be FLAC_MIN_HEADERS buffered in the fifo before
it drains . This is allocated early to avoid slow reallocation . */
fpc - > fifo_buf = av_fifo_alloc_array ( FLAC_MIN_HEADERS + 3 , FLAC_AVG_FRAME_SIZE ) ;
if ( ! fpc - > fifo_buf ) {
ret = flac_fifo_alloc ( & fpc - > fifo_buf , ( FLAC_MIN_HEADERS + 3 ) * FLAC_AVG_FRAME_SIZE ) ;
if ( ret < 0 ) {
av_log ( fpc - > avctx , AV_LOG_ERROR ,
" couldn't allocate fifo_buf \n " ) ;
return AVERROR ( ENOMEM ) ;
@ -765,7 +883,7 @@ static void flac_parse_close(AVCodecParserContext *c)
curr = temp ;
}
fpc - > headers = NULL ;
av_fifo_freep ( & fpc - > fifo_buf ) ;
flac_fifo_free ( & fpc - > fifo_buf ) ;
av_freep ( & fpc - > wrap_buf ) ;
}