static int decode_frame(AVCodecContext *avctx,
                        void *data, int *got_frame, AVPacket *avpkt)
{
    TiffContext *const s = avctx->priv_data;
    AVFrame *const p = data;
    unsigned off;
    int id, le, ret;
    int i, j, entries, stride;
    unsigned soff, ssize;
    uint8_t *dst;
    GetByteContext stripsizes;
    GetByteContext stripdata;

    bytestream2_init(&s->gb, avpkt->data, avpkt->size);

    // parse image header
    if (avpkt->size < 8)
        return AVERROR_INVALIDDATA;
    id = bytestream2_get_le16(&s->gb);
    if (id == 0x4949)
        le = 1;
    else if (id == 0x4D4D)
        le = 0;
    else {
        av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n");
        return AVERROR_INVALIDDATA;
    }
    s->le         = le;
    s->invert     = 0;
    s->compr      = TIFF_RAW;
    s->fill_order = 0;
    // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number
    // that further identifies the file as a TIFF file"
    if (tget_short(&s->gb, le) != 42) {
        av_log(avctx, AV_LOG_ERROR,
               "The answer to life, universe and everything is not correct!\n");
        return AVERROR_INVALIDDATA;
    }
    // Reset these offsets so we can tell if they were set this frame
    s->stripsizesoff = s->strippos = 0;
    /* parse image file directory */
    off = tget_long(&s->gb, le);
    if (off >= UINT_MAX - 14 || avpkt->size < off + 14) {
        av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
        return AVERROR_INVALIDDATA;
    }
    bytestream2_seek(&s->gb, off, SEEK_SET);
    entries = tget_short(&s->gb, le);
    for (i = 0; i < entries; i++) {
        if ((ret = tiff_decode_tag(s)) < 0)
            return ret;
    }
    if (!s->strippos && !s->stripoff) {
        av_log(avctx, AV_LOG_ERROR, "Image data is missing\n");
        return AVERROR_INVALIDDATA;
    }
    /* now we have the data and may start decoding */
    if ((ret = init_image(s, p)) < 0)
        return ret;

    if (s->strips == 1 && !s->stripsize) {
        av_log(avctx, AV_LOG_WARNING, "Image data size missing\n");
        s->stripsize = avpkt->size - s->stripoff;
    }
    stride = p->linesize[0];
    dst    = p->data[0];

    if (s->stripsizesoff) {
        if (s->stripsizesoff >= avpkt->size)
            return AVERROR_INVALIDDATA;
        bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff,
                         avpkt->size - s->stripsizesoff);
    }
    if (s->strippos) {
        if (s->strippos >= avpkt->size)
            return AVERROR_INVALIDDATA;
        bytestream2_init(&stripdata, avpkt->data + s->strippos,
                         avpkt->size - s->strippos);
    }

    for (i = 0; i < s->height; i += s->rps) {
        if (s->stripsizesoff)
            ssize = tget(&stripsizes, s->sstype, le);
        else
            ssize = s->stripsize;

        if (s->strippos)
            soff = tget(&stripdata, s->sot, le);
        else
            soff = s->stripoff;

        if (soff > avpkt->size || ssize > avpkt->size - soff) {
            av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
            return AVERROR_INVALIDDATA;
        }
        if ((ret = tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize,
                                     FFMIN(s->rps, s->height - i))) < 0) {
            if (avctx->err_recognition & AV_EF_EXPLODE)
                return ret;
            break;
        }
        dst += s->rps * stride;
    }
    if (s->predictor == 2) {
        dst   = p->data[0];
        soff  = s->bpp >> 3;
        ssize = s->width * soff;
        for (i = 0; i < s->height; i++) {
            for (j = soff; j < ssize; j++)
                dst[j] += dst[j - soff];
            dst += stride;
        }
    }

    if (s->invert) {
        dst = p->data[0];
        for (i = 0; i < s->height; i++) {
            for (j = 0; j < p->linesize[0]; j++)
                dst[j] = 255 - dst[j];
            dst += stride;
        }
    }
    *got_frame = 1;

    return avpkt->size;
}