static int ape_decode_frame(AVCodecContext *avctx,
                            void *data, int *data_size,
                            AVPacket *avpkt)
{
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
    APEContext *s = avctx->priv_data;
    int16_t *samples = data;
    uint32_t nblocks;
    int i;
    int blockstodecode, out_size;
    int bytes_used;

    /* this should never be negative, but bad things will happen if it is, so
       check it just to make sure. */
    av_assert0(s->samples >= 0);

    if(!s->samples){
        uint32_t offset;
        void *tmp_data;

        if (buf_size < 8) {
            av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
            return AVERROR_INVALIDDATA;
        }

        tmp_data = av_realloc(s->data, FFALIGN(buf_size, 4));
        if (!tmp_data)
            return AVERROR(ENOMEM);
        s->data = tmp_data;
        s->dsp.bswap_buf((uint32_t*)s->data, (const uint32_t*)buf, buf_size >> 2);
        s->ptr = s->last_ptr = s->data;
        s->data_end = s->data + buf_size;

        nblocks = bytestream_get_be32(&s->ptr);
        offset  = bytestream_get_be32(&s->ptr);
        if (offset > 3) {
            av_log(avctx, AV_LOG_ERROR, "Incorrect offset passed\n");
            s->data = NULL;
            return AVERROR_INVALIDDATA;
        }
        if (s->data_end - s->ptr < offset) {
            av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
            return AVERROR_INVALIDDATA;
        }
        s->ptr += offset;

        if (!nblocks || nblocks > INT_MAX) {
            av_log(avctx, AV_LOG_ERROR, "Invalid sample count: %u.\n", nblocks);
            return AVERROR_INVALIDDATA;
        }
        s->samples = nblocks;

        memset(s->decoded0,  0, sizeof(s->decoded0));
        memset(s->decoded1,  0, sizeof(s->decoded1));

        /* Initialize the frame decoder */
        if (init_frame_decoder(s) < 0) {
            av_log(avctx, AV_LOG_ERROR, "Error reading frame header\n");
            return AVERROR_INVALIDDATA;
        }
    }

    if (!s->data) {
        *data_size = 0;
        return buf_size;
    }

    nblocks = s->samples;
    blockstodecode = FFMIN(BLOCKS_PER_LOOP, nblocks);

    out_size = blockstodecode * avctx->channels *
               av_get_bytes_per_sample(avctx->sample_fmt);
    if (*data_size < out_size) {
        av_log(avctx, AV_LOG_ERROR, "Output buffer is too small.\n");
        return AVERROR(EINVAL);
    }

    s->error=0;

    if ((s->channels == 1) || (s->frameflags & APE_FRAMECODE_PSEUDO_STEREO))
        ape_unpack_mono(s, blockstodecode);
    else
        ape_unpack_stereo(s, blockstodecode);
    emms_c();

    if (s->error) {
        s->samples=0;
        av_log(avctx, AV_LOG_ERROR, "Error decoding frame\n");
        return AVERROR_INVALIDDATA;
    }

    for (i = 0; i < blockstodecode; i++) {
        *samples++ = s->decoded0[i];
        if(s->channels == 2)
            *samples++ = s->decoded1[i];
    }

    s->samples -= blockstodecode;

    bytes_used = s->samples ? s->ptr - s->last_ptr : buf_size;
    s->last_ptr = s->ptr;

    *data_size = out_size;
    return bytes_used;
}