Ejemplo n.º 1
0
static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
                           int *poutbuf_size)
{
    FLACHeaderMarker *header = fpc->best_header;
    FLACHeaderMarker *child  = header->best_child;
    if (!child) {
        *poutbuf_size = av_fifo_size(fpc->fifo_buf) - header->offset;
    } else {
        *poutbuf_size = child->offset - header->offset;

        /* If the child has suspicious changes, log them */
        check_header_mismatch(fpc, header, child, 0);
    }

    if (header->fi.channels != fpc->avctx->channels ||
        !fpc->avctx->channel_layout) {
        fpc->avctx->channels = header->fi.channels;
        ff_flac_set_channel_layout(fpc->avctx);
    }
    fpc->avctx->sample_rate = header->fi.samplerate;
    fpc->pc->duration       = header->fi.blocksize;
    *poutbuf = flac_fifo_read_wrap(fpc, header->offset, *poutbuf_size,
                                        &fpc->wrap_buf,
                                        &fpc->wrap_buf_allocated_size);

    fpc->best_header_valid = 0;
    /* 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 0;
}
Ejemplo n.º 2
0
static int find_headers_search_validate(FLACParseContext *fpc, int offset)
{
    FLACFrameInfo fi;
    uint8_t *header_buf;
    int size = 0;
    header_buf = flac_fifo_read_wrap(fpc, offset,
                                     MAX_FRAME_HEADER_SIZE,
                                     &fpc->wrap_buf,
                                     &fpc->wrap_buf_allocated_size);
    if (frame_header_is_valid(fpc->avctx, header_buf, &fi)) {
        FLACHeaderMarker **end_handle = &fpc->headers;
        int i;

        size = 0;
        while (*end_handle) {
            end_handle = &(*end_handle)->next;
            size++;
        }

        *end_handle = av_mallocz(sizeof(**end_handle));
        if (!*end_handle) {
            av_log(fpc->avctx, AV_LOG_ERROR,
                   "couldn't allocate FLACHeaderMarker\n");
            return AVERROR(ENOMEM);
        }
        (*end_handle)->fi           = fi;
        (*end_handle)->offset       = offset;
        (*end_handle)->link_penalty = av_malloc(sizeof(int) *
                                            FLAC_MAX_SEQUENTIAL_HEADERS);
        if (!(*end_handle)->link_penalty) {
            av_freep(end_handle);
            av_log(fpc->avctx, AV_LOG_ERROR,
                   "couldn't allocate link_penalty\n");
            return AVERROR(ENOMEM);
        }

        for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++)
            (*end_handle)->link_penalty[i] = FLAC_HEADER_NOT_PENALIZED_YET;

        fpc->nb_headers_found++;
        size++;
    }
    return size;
}
Ejemplo n.º 3
0
static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
                      const uint8_t **poutbuf, int *poutbuf_size,
                      const uint8_t *buf, int buf_size)
{
    FLACParseContext *fpc = s->priv_data;
    FLACHeaderMarker *curr;
    int nb_headers;
    const uint8_t *read_end   = buf;
    const uint8_t *read_start = buf;

    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
        FLACFrameInfo fi;
        if (frame_header_is_valid(avctx, buf, &fi))
            s->duration = fi.blocksize;
        *poutbuf      = buf;
        *poutbuf_size = buf_size;
        return buf_size;
    }

    fpc->avctx = avctx;
    if (fpc->best_header_valid)
        return get_best_header(fpc, poutbuf, poutbuf_size);

    /* If a best_header was found last call remove it with the buffer data. */
    if (fpc->best_header && fpc->best_header->best_child) {
        FLACHeaderMarker *temp;
        FLACHeaderMarker *best_child = fpc->best_header->best_child;

        /* Remove headers in list until the end of the best_header. */
        for (curr = fpc->headers; curr != best_child; curr = temp) {
            if (curr != fpc->best_header) {
                av_log(avctx, AV_LOG_DEBUG,
                       "dropping low score %i frame header from offset %i to %i\n",
                       curr->max_score, curr->offset, curr->next->offset);
            }
            temp = curr->next;
            av_freep(&curr->link_penalty);
            av_free(curr);
            fpc->nb_headers_buffered--;
        }
        /* Release returned data from ring buffer. */
        av_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)
            curr->offset -= best_child->offset;

        fpc->nb_headers_buffered--;
        best_child->offset = 0;
        fpc->headers       = best_child;
        if (fpc->nb_headers_buffered >= FLAC_MIN_HEADERS) {
            fpc->best_header = best_child;
            return get_best_header(fpc, poutbuf, poutbuf_size);
        }
        fpc->best_header   = NULL;
    } else if (fpc->best_header) {
        /* No end frame no need to delete the buffer; probably eof */
        FLACHeaderMarker *temp;

        for (curr = fpc->headers; curr != fpc->best_header; curr = temp) {
            temp = curr->next;
            av_freep(&curr->link_penalty);
            av_free(curr);
        }
        fpc->headers = fpc->best_header->next;
        av_freep(&fpc->best_header->link_penalty);
        av_freep(&fpc->best_header);
    }

    /* Find and score new headers. */
    while ((buf && read_end < buf + buf_size &&
            fpc->nb_headers_buffered < FLAC_MIN_HEADERS)
           || (!buf && !fpc->end_padded)) {
        int start_offset;

        /* Pad the end once if EOF, to check the final region for headers. */
        if (!buf) {
            fpc->end_padded      = 1;
            buf_size = MAX_FRAME_HEADER_SIZE;
            read_end = read_start + MAX_FRAME_HEADER_SIZE;
        } else {
            /* The maximum read size is the upper-bound of what the parser
               needs to have the required number of frames buffered */
            int nb_desired = FLAC_MIN_HEADERS - fpc->nb_headers_buffered + 1;
            read_end       = read_end + FFMIN(buf + buf_size - read_end,
                                              nb_desired * FLAC_AVG_FRAME_SIZE);
        }

        if (!av_fifo_space(fpc->fifo_buf) &&
            av_fifo_size(fpc->fifo_buf) / FLAC_AVG_FRAME_SIZE >
            fpc->nb_headers_buffered * 10) {
            /* There is less than one valid flac header buffered for 10 headers
             * buffered. Therefore the fifo is most likely filled with invalid
             * data and the input is not a flac file. */
            goto handle_error;
        }

        /* Fill the buffer. */
        if (av_fifo_realloc2(fpc->fifo_buf,
                             (read_end - read_start) + av_fifo_size(fpc->fifo_buf)) < 0) {
            av_log(avctx, AV_LOG_ERROR,
                   "couldn't reallocate buffer of size %td\n",
                   (read_end - read_start) + av_fifo_size(fpc->fifo_buf));
            goto handle_error;
        }

        if (buf) {
            av_fifo_generic_write(fpc->fifo_buf, (void*) read_start,
                                  read_end - read_start, NULL);
        } else {
            int8_t pad[MAX_FRAME_HEADER_SIZE] = { 0 };
            av_fifo_generic_write(fpc->fifo_buf, pad, sizeof(pad), NULL);
        }

        /* Tag headers and update sequences. */
        start_offset = av_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);

        if (nb_headers < 0) {
            av_log(avctx, AV_LOG_ERROR,
                   "find_new_headers couldn't allocate FLAC header\n");
            goto handle_error;
        }

        fpc->nb_headers_buffered = nb_headers;
        /* Wait till FLAC_MIN_HEADERS to output a valid frame. */
        if (!fpc->end_padded && fpc->nb_headers_buffered < FLAC_MIN_HEADERS) {
            if (buf && read_end < buf + buf_size) {
                read_start = read_end;
                continue;
            } else {
                goto handle_error;
            }
        }

        /* If headers found, update the scores since we have longer chains. */
        if (fpc->end_padded || fpc->nb_headers_found)
            score_sequences(fpc);

        /* restore the state pre-padding */
        if (fpc->end_padded) {
            /* 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) {
                fpc->fifo_buf->wptr += fpc->fifo_buf->end -
                    fpc->fifo_buf->buffer;
            }
            buf_size = 0;
            read_start = read_end = NULL;
        }
    }

    curr = fpc->headers;
    for (curr = fpc->headers; curr; curr = curr->next)
        if (!fpc->best_header || curr->max_score > fpc->best_header->max_score)
            fpc->best_header = curr;

    if (fpc->best_header) {
        fpc->best_header_valid = 1;
        if (fpc->best_header->offset > 0) {
            /* Output a junk frame. */
            av_log(avctx, AV_LOG_DEBUG, "Junk frame till offset %i\n",
                   fpc->best_header->offset);

            /* Set duration to 0. It is unknown or invalid in a junk frame. */
            s->duration = 0;
            *poutbuf_size     = fpc->best_header->offset;
            *poutbuf          = flac_fifo_read_wrap(fpc, 0, *poutbuf_size,
                                                    &fpc->wrap_buf,
                                                    &fpc->wrap_buf_allocated_size);
            return buf_size ? (read_end - buf) : (fpc->best_header->offset -
                                           av_fifo_size(fpc->fifo_buf));
        }
        if (!buf_size)
            return get_best_header(fpc, poutbuf, poutbuf_size);
    }

handle_error:
    *poutbuf      = NULL;
    *poutbuf_size = 0;
    return read_end - buf;
}