static int decode_frame_headers(Indeo3DecodeContext *ctx, AVCodecContext *avctx,

                                const uint8_t *buf, int buf_size)

{

    GetByteContext gb;

    const uint8_t   *bs_hdr;

    uint32_t        frame_num, word2, check_sum, data_size;

    uint32_t        y_offset, u_offset, v_offset, starts[3], ends[3];

    uint16_t        height, width;

    int             i, j;



    bytestream2_init(&gb, buf, buf_size);



    /* parse and check the OS header */

    frame_num = bytestream2_get_le32(&gb);

    word2     = bytestream2_get_le32(&gb);

    check_sum = bytestream2_get_le32(&gb);

    data_size = bytestream2_get_le32(&gb);



    if ((frame_num ^ word2 ^ data_size ^ OS_HDR_ID) != check_sum) {

        av_log(avctx, AV_LOG_ERROR, "OS header checksum mismatch!\n");

        return AVERROR_INVALIDDATA;

    }



    /* parse the bitstream header */

    bs_hdr = gb.buffer;



    if (bytestream2_get_le16(&gb) != 32) {

        av_log(avctx, AV_LOG_ERROR, "Unsupported codec version!\n");

        return AVERROR_INVALIDDATA;

    }



    ctx->frame_num   =  frame_num;

    ctx->frame_flags =  bytestream2_get_le16(&gb);

    ctx->data_size   = (bytestream2_get_le32(&gb) + 7) >> 3;

    ctx->cb_offset   =  bytestream2_get_byte(&gb);



    if (ctx->data_size == 16)

        return 4;

    if (ctx->data_size > buf_size)

        ctx->data_size = buf_size;



    bytestream2_skip(&gb, 3); // skip reserved byte and checksum



    /* check frame dimensions */

    height = bytestream2_get_le16(&gb);

    width  = bytestream2_get_le16(&gb);

    if (av_image_check_size(width, height, 0, avctx))

        return AVERROR_INVALIDDATA;



    if (width != ctx->width || height != ctx->height) {

        int res;



        av_dlog(avctx, "Frame dimensions changed!\n");



        if (width  < 16 || width  > 640 ||

            height < 16 || height > 480 ||

            width  &  3 || height &   3) {

            av_log(avctx, AV_LOG_ERROR,

                   "Invalid picture dimensions: %d x %d!\n", width, height);

            return AVERROR_INVALIDDATA;

        }



        ctx->width  = width;

        ctx->height = height;



        free_frame_buffers(ctx);

        if ((res = allocate_frame_buffers(ctx, avctx)) < 0)

             return res;

        avcodec_set_dimensions(avctx, width, height);

    }



    y_offset = bytestream2_get_le32(&gb);

    v_offset = bytestream2_get_le32(&gb);

    u_offset = bytestream2_get_le32(&gb);

    bytestream2_skip(&gb, 4);



    /* unfortunately there is no common order of planes in the buffer */

    /* so we use that sorting algo for determining planes data sizes  */

    starts[0] = y_offset;

    starts[1] = v_offset;

    starts[2] = u_offset;



    for (j = 0; j < 3; j++) {

        ends[j] = ctx->data_size;

        for (i = 2; i >= 0; i--)

            if (starts[i] < ends[j] && starts[i] > starts[j])

                ends[j] = starts[i];

    }



    ctx->y_data_size = ends[0] - starts[0];

    ctx->v_data_size = ends[1] - starts[1];

    ctx->u_data_size = ends[2] - starts[2];

    if (FFMAX3(y_offset, v_offset, u_offset) >= ctx->data_size - 16 ||

        FFMIN3(y_offset, v_offset, u_offset) < gb.buffer - bs_hdr + 16 ||

        FFMIN3(ctx->y_data_size, ctx->v_data_size, ctx->u_data_size) <= 0) {

        av_log(avctx, AV_LOG_ERROR, "One of the y/u/v offsets is invalid\n");

        return AVERROR_INVALIDDATA;

    }



    ctx->y_data_ptr = bs_hdr + y_offset;

    ctx->v_data_ptr = bs_hdr + v_offset;

    ctx->u_data_ptr = bs_hdr + u_offset;

    ctx->alt_quant  = gb.buffer;



    if (ctx->data_size == 16) {

        av_log(avctx, AV_LOG_DEBUG, "Sync frame encountered!\n");

        return 16;

    }



    if (ctx->frame_flags & BS_8BIT_PEL) {

        avpriv_request_sample(avctx, "8-bit pixel format");

        return AVERROR_PATCHWELCOME;

    }



    if (ctx->frame_flags & BS_MV_X_HALF || ctx->frame_flags & BS_MV_Y_HALF) {

        avpriv_request_sample(avctx, "Halfpel motion vectors");

        return AVERROR_PATCHWELCOME;

    }



    return 0;

}
