diff options
Diffstat (limited to 'libavcodec/flac_parser.c')
-rw-r--r-- | libavcodec/flac_parser.c | 109 |
1 files changed, 79 insertions, 30 deletions
diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index bf2c11821b..68c915e9ce 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -2,20 +2,20 @@ * FLAC parser * Copyright (c) 2010 Michael Chinen * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -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; @@ -469,7 +489,18 @@ 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; + else if (header->best_child) + fpc->pc->pts = header->fi.frame_or_sample_num * header->fi.blocksize; + } + 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) @@ -489,8 +520,16 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { FLACFrameInfo fi; - if (frame_header_is_valid(avctx, buf, &fi)) + if (frame_header_is_valid(avctx, buf, &fi)) { s->duration = fi.blocksize; + if (!avctx->sample_rate) + avctx->sample_rate = fi.samplerate; + if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){ + fpc->pc->pts = fi.frame_or_sample_num; + if (!fi.is_var_size) + fpc->pc->pts *= fi.blocksize; + } + } *poutbuf = buf; *poutbuf_size = buf_size; return buf_size; @@ -546,14 +585,18 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, av_freep(&fpc->best_header); } - /* Find and score new headers. */ - while ((buf && read_end < buf + buf_size && + /* Find and score new headers. */ + /* buf_size is to zero when padding, so check for this since we do */ + /* not want to try to read more input once we have found the end. */ + /* Note that as (non-modified) parameters, buf can be non-NULL, */ + /* while buf_size is 0. */ + while ((buf && buf_size && read_end < buf + buf_size && fpc->nb_headers_buffered < FLAC_MIN_HEADERS) - || (!buf && !fpc->end_padded)) { + || ((!buf || !buf_size) && !fpc->end_padded)) { int start_offset; /* Pad the end once if EOF, to check the final region for headers. */ - if (!buf) { + if (!buf || !buf_size) { fpc->end_padded = 1; buf_size = MAX_FRAME_HEADER_SIZE; read_end = read_start + MAX_FRAME_HEADER_SIZE; @@ -566,15 +609,15 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx, } /* Fill the buffer. */ - if (av_fifo_realloc2(fpc->fifo_buf, - (read_end - read_start) + av_fifo_size(fpc->fifo_buf)) < 0) { + 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 %td\n", + "couldn't reallocate buffer of size %"PTRDIFF_SPECIFIER"\n", (read_end - read_start) + av_fifo_size(fpc->fifo_buf)); goto handle_error; } - if (buf) { + if (buf && buf_size) { av_fifo_generic_write(fpc->fifo_buf, (void*) read_start, read_end - read_start, NULL); } else { @@ -611,10 +654,11 @@ 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; /* HACK: drain the tail of the fifo */ fpc->fifo_buf->wptr -= MAX_FRAME_HEADER_SIZE; fpc->fifo_buf->wndx -= MAX_FRAME_HEADER_SIZE; - if (fpc->fifo_buf->wptr < 0) { + if (warp) { fpc->fifo_buf->wptr += fpc->fifo_buf->end - fpc->fifo_buf->buffer; } @@ -624,9 +668,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; @@ -660,7 +707,9 @@ static av_cold int flac_parse_init(AVCodecParserContext *c) 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(FLAC_AVG_FRAME_SIZE * (FLAC_MIN_HEADERS + 3)); + fpc->fifo_buf = av_fifo_alloc_array(FLAC_MIN_HEADERS + 3, FLAC_AVG_FRAME_SIZE); + if (!fpc->fifo_buf) + return AVERROR(ENOMEM); return 0; } @@ -675,7 +724,7 @@ static void flac_parse_close(AVCodecParserContext *c) av_free(curr); curr = temp; } - av_fifo_free(fpc->fifo_buf); + av_fifo_freep(&fpc->fifo_buf); av_free(fpc->wrap_buf); } |