static int read_access_unit(AVCodecContext *avctx, void* data, int *data_size,

                            AVPacket *avpkt)

{

    const uint8_t *buf = avpkt->data;

    int buf_size = avpkt->size;

    MLPDecodeContext *m = avctx->priv_data;

    GetBitContext gb;

    unsigned int length, substr;

    unsigned int substream_start;

    unsigned int header_size = 4;

    unsigned int substr_header_size = 0;

    uint8_t substream_parity_present[MAX_SUBSTREAMS];

    uint16_t substream_data_len[MAX_SUBSTREAMS];

    uint8_t parity_bits;



    if (buf_size < 4)

        return 0;



    length = (AV_RB16(buf) & 0xfff) * 2;



    if (length > buf_size)

        return -1;



    init_get_bits(&gb, (buf + 4), (length - 4) * 8);



    m->is_major_sync_unit = 0;

    if (show_bits_long(&gb, 31) == (0xf8726fba >> 1)) {

        if (read_major_sync(m, &gb) < 0)

            goto error;

        m->is_major_sync_unit = 1;

        header_size += 28;

    }



    if (!m->params_valid) {

        av_log(m->avctx, AV_LOG_WARNING,

               "Stream parameters not seen; skipping frame.\n");

        *data_size = 0;

        return length;

    }



    substream_start = 0;



    for (substr = 0; substr < m->num_substreams; substr++) {

        int extraword_present, checkdata_present, end, nonrestart_substr;



        extraword_present = get_bits1(&gb);

        nonrestart_substr = get_bits1(&gb);

        checkdata_present = get_bits1(&gb);

        skip_bits1(&gb);



        end = get_bits(&gb, 12) * 2;



        substr_header_size += 2;



        if (extraword_present) {

            if (m->avctx->codec_id == CODEC_ID_MLP) {

                av_log(m->avctx, AV_LOG_ERROR, "There must be no extraword for MLP.\n");

                goto error;

            }

            skip_bits(&gb, 16);

            substr_header_size += 2;

        }



        if (!(nonrestart_substr ^ m->is_major_sync_unit)) {

            av_log(m->avctx, AV_LOG_ERROR, "Invalid nonrestart_substr.\n");

            goto error;

        }



        if (end + header_size + substr_header_size > length) {

            av_log(m->avctx, AV_LOG_ERROR,

                   "Indicated length of substream %d data goes off end of "

                   "packet.\n", substr);

            end = length - header_size - substr_header_size;

        }



        if (end < substream_start) {

            av_log(avctx, AV_LOG_ERROR,

                   "Indicated end offset of substream %d data "

                   "is smaller than calculated start offset.\n",

                   substr);

            goto error;

        }



        if (substr > m->max_decoded_substream)

            continue;



        substream_parity_present[substr] = checkdata_present;

        substream_data_len[substr] = end - substream_start;

        substream_start = end;

    }



    parity_bits  = ff_mlp_calculate_parity(buf, 4);

    parity_bits ^= ff_mlp_calculate_parity(buf + header_size, substr_header_size);



    if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) {

        av_log(avctx, AV_LOG_ERROR, "Parity check failed.\n");

        goto error;

    }



    buf += header_size + substr_header_size;



    for (substr = 0; substr <= m->max_decoded_substream; substr++) {

        SubStream *s = &m->substream[substr];

        init_get_bits(&gb, buf, substream_data_len[substr] * 8);



        m->matrix_changed = 0;

        memset(m->filter_changed, 0, sizeof(m->filter_changed));



        s->blockpos = 0;

        do {

            unsigned int ch;



            if (get_bits1(&gb)) {

                if (get_bits1(&gb)) {

                    /* A restart header should be present. */

                    if (read_restart_header(m, &gb, buf, substr) < 0)

                        goto next_substr;

                    s->restart_seen = 1;

                }



                if (!s->restart_seen) {

                    goto next_substr;

                }



                if (read_decoding_params(m, &gb, substr) < 0)

                    goto next_substr;

            }



            if (m->matrix_changed > 1) {

                av_log(m->avctx, AV_LOG_ERROR, "Matrices may change only once per access unit.\n");

                goto next_substr;

            }

            for (ch = 0; ch < s->max_channel; ch++)

                if (m->filter_changed[ch][FIR] > 1 ||

                    m->filter_changed[ch][IIR] > 1) {

                    av_log(m->avctx, AV_LOG_ERROR, "Filters may change only once per access unit.\n");

                    goto next_substr;

                }



            if (!s->restart_seen) {

                goto next_substr;

            }



            if (read_block_data(m, &gb, substr) < 0)

                return -1;



            if (get_bits_count(&gb) >= substream_data_len[substr] * 8)

                goto substream_length_mismatch;



        } while (!get_bits1(&gb));



        skip_bits(&gb, (-get_bits_count(&gb)) & 15);

        if (substream_data_len[substr] * 8 - get_bits_count(&gb) >= 32) {

            int shorten_by;



            if (get_bits(&gb, 16) != 0xD234)

                return -1;



            shorten_by = get_bits(&gb, 16);

            if      (m->avctx->codec_id == CODEC_ID_TRUEHD && shorten_by  & 0x2000)

                s->blockpos -= FFMIN(shorten_by & 0x1FFF, s->blockpos);

            else if (m->avctx->codec_id == CODEC_ID_MLP    && shorten_by != 0xD234)

                return -1;



            if (substr == m->max_decoded_substream)

                av_log(m->avctx, AV_LOG_INFO, "End of stream indicated.\n");

        }

        if (substream_parity_present[substr]) {

            uint8_t parity, checksum;



            if (substream_data_len[substr] * 8 - get_bits_count(&gb) != 16)

                goto substream_length_mismatch;



            parity   = ff_mlp_calculate_parity(buf, substream_data_len[substr] - 2);

            checksum = ff_mlp_checksum8       (buf, substream_data_len[substr] - 2);



            if ((get_bits(&gb, 8) ^ parity) != 0xa9    )

                av_log(m->avctx, AV_LOG_ERROR, "Substream %d parity check failed.\n", substr);

            if ( get_bits(&gb, 8)           != checksum)

                av_log(m->avctx, AV_LOG_ERROR, "Substream %d checksum failed.\n"    , substr);

        }

        if (substream_data_len[substr] * 8 != get_bits_count(&gb)) {

            goto substream_length_mismatch;

        }



next_substr:

        if (!s->restart_seen) {

            av_log(m->avctx, AV_LOG_ERROR,

                   "No restart header present in substream %d.\n", substr);

        }



        buf += substream_data_len[substr];

    }



    rematrix_channels(m, m->max_decoded_substream);



    if (output_data(m, m->max_decoded_substream, data, data_size) < 0)

        return -1;



    return length;



substream_length_mismatch:

    av_log(m->avctx, AV_LOG_ERROR, "substream %d length mismatch\n", substr);

    return -1;



error:

    m->params_valid = 0;

    return -1;

}
