From fc736a99eae194c85fe344a4db895c1cd3493d45 Mon Sep 17 00:00:00 2001 From: Michael Chinen Date: Fri, 28 Jun 2013 14:16:39 +0900 Subject: flac_parser.c: fix case when final frame is a false positive Should fix https://ffmpeg.org/trac/ffmpeg/ticket/2552 Only did minimal testing on a few files and fate. Signed-off-by: Michael Niedermayer --- libavcodec/flac_parser.c | 54 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index 2996398694..ded7bde2aa 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -87,6 +87,8 @@ typedef struct FLACParseContext { int end_padded; /**< specifies if fifo_buf's end is padded */ uint8_t *wrap_buf; /**< general fifo read buffer when wrapped */ int wrap_buf_allocated_size; /**< actual allocated size of the buffer */ + FLACFrameInfo last_fi; /**< last decoded frame header info */ + int last_fi_valid; /**< set if last_fi is valid */ } FLACParseContext; static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf, @@ -267,13 +269,12 @@ static int find_new_headers(FLACParseContext *fpc, int search_start) return size; } -static int check_header_mismatch(FLACParseContext *fpc, - FLACHeaderMarker *header, - FLACHeaderMarker *child, - int log_level_offset) +static int check_header_fi_mismatch(FLACParseContext *fpc, + FLACFrameInfo *header_fi, + FLACFrameInfo *child_fi, + int log_level_offset) { - FLACFrameInfo *header_fi = &header->fi, *child_fi = &child->fi; - int deduction = 0, deduction_expected = 0, i; + int deduction = 0; if (child_fi->samplerate != header_fi->samplerate) { deduction += FLAC_HEADER_CHANGED_PENALTY; av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset, @@ -288,13 +289,25 @@ static int check_header_mismatch(FLACParseContext *fpc, /* Changing blocking strategy not allowed per the spec */ deduction += FLAC_HEADER_BASE_SCORE; av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset, - "blocking strategy change detected in adjacent frames\n"); + "blocking strategy change detected in adjacent frames\n"); } if (child_fi->channels != header_fi->channels) { deduction += FLAC_HEADER_CHANGED_PENALTY; av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset, - "number of channels change detected in adjacent frames\n"); + "number of channels change detected in adjacent frames\n"); } + return deduction; +} + +static int check_header_mismatch(FLACParseContext *fpc, + FLACHeaderMarker *header, + FLACHeaderMarker *child, + int log_level_offset) +{ + FLACFrameInfo *header_fi = &header->fi, *child_fi = &child->fi; + int deduction, deduction_expected = 0, i; + deduction = check_header_fi_mismatch(fpc, header_fi, child_fi, + log_level_offset); /* Check sample and frame numbers. */ if ((child_fi->frame_or_sample_num - header_fi->frame_or_sample_num != header_fi->blocksize) && @@ -399,11 +412,18 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header) FLACHeaderMarker *child; int dist = 0; int child_score; - + int base_score = FLAC_HEADER_BASE_SCORE; if (header->max_score != FLAC_HEADER_NOT_SCORED_YET) return header->max_score; - header->max_score = FLAC_HEADER_BASE_SCORE; + /* Modify the base score with changes from the last output header */ + if (fpc->last_fi_valid) { + /* Silence the log since this will be repeated if selected */ + base_score -= check_header_fi_mismatch(fpc, &fpc->last_fi, &header->fi, + AV_LOG_DEBUG); + } + + header->max_score = base_score; /* Check and compute the children's scores. */ child = header->next; @@ -419,7 +439,7 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header) if (FLAC_HEADER_BASE_SCORE + child_score > header->max_score) { /* Keep the child because the frame scoring is dynamic. */ header->best_child = child; - header->max_score = FLAC_HEADER_BASE_SCORE + child_score; + header->max_score = base_score + child_score; } child = child->next; } @@ -430,7 +450,7 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header) static void score_sequences(FLACParseContext *fpc) { FLACHeaderMarker *curr; - int best_score = FLAC_HEADER_NOT_SCORED_YET; + int best_score = 0;//FLAC_HEADER_NOT_SCORED_YET; /* First pass to clear all old scores. */ for (curr = fpc->headers; curr; curr = curr->next) curr->max_score = FLAC_HEADER_NOT_SCORED_YET; @@ -470,6 +490,9 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf, &fpc->wrap_buf_allocated_size); fpc->best_header_valid = 0; + fpc->last_fi_valid = 1; + fpc->last_fi = header->fi; + /* 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) @@ -629,9 +652,12 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, } curr = fpc->headers; - for (curr = fpc->headers; curr; curr = curr->next) - if (!fpc->best_header || curr->max_score > fpc->best_header->max_score) + for (curr = fpc->headers; curr; curr = curr->next) { + if (curr->max_score > 0 && + (!fpc->best_header || curr->max_score > fpc->best_header->max_score)) { fpc->best_header = curr; + } + } if (fpc->best_header) { fpc->best_header_valid = 1; -- cgit v1.2.3