int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)

{

    const SPS *sps;

    const PPS *pps;

    unsigned int first_mb_in_slice;

    unsigned int pps_id;

    int ret;

    unsigned int slice_type, tmp, i, j;

    int last_pic_structure, last_pic_droppable;

    int needs_reinit = 0;

    int field_pic_flag, bottom_field_flag;

    int frame_num, droppable, picture_structure;

    int mb_aff_frame = 0;

    h->qpel_put = h->h264qpel.put_h264_qpel_pixels_tab;

    h->qpel_avg = h->h264qpel.avg_h264_qpel_pixels_tab;

    first_mb_in_slice = get_ue_golomb(&sl->gb);

    if (first_mb_in_slice == 0) { // FIXME better field boundary detection

        if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) {

            ff_h264_field_end(h, sl, 1);

        }

        h->current_slice = 0;

        if (!h->first_field) {

            if (h->cur_pic_ptr && !h->droppable) {

                ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,

                                          h->picture_structure == PICT_BOTTOM_FIELD);

            }

            h->cur_pic_ptr = NULL;

        }

    }

    slice_type = get_ue_golomb_31(&sl->gb);

    if (slice_type > 9) {

        av_log(h->avctx, AV_LOG_ERROR,

               "slice type %d too large at %d\n",

               slice_type, first_mb_in_slice);

        return AVERROR_INVALIDDATA;

    }

    if (slice_type > 4) {

        slice_type -= 5;

        sl->slice_type_fixed = 1;

    } else

        sl->slice_type_fixed = 0;

    slice_type         = ff_h264_golomb_to_pict_type[slice_type];

    sl->slice_type     = slice_type;

    sl->slice_type_nos = slice_type & 3;

    if (h->nal_unit_type  == NAL_IDR_SLICE &&

        sl->slice_type_nos != AV_PICTURE_TYPE_I) {

        av_log(h->avctx, AV_LOG_ERROR, "A non-intra slice in an IDR NAL unit.\n");

        return AVERROR_INVALIDDATA;

    }

    // to make a few old functions happy, it's wrong though

    if (!h->setup_finished)

        h->pict_type = sl->slice_type;

    pps_id = get_ue_golomb(&sl->gb);

    if (pps_id >= MAX_PPS_COUNT) {

        av_log(h->avctx, AV_LOG_ERROR, "pps_id %u out of range\n", pps_id);

        return AVERROR_INVALIDDATA;

    }

    if (!h->ps.pps_list[pps_id]) {

        av_log(h->avctx, AV_LOG_ERROR,

               "non-existing PPS %u referenced\n",

               pps_id);

        return AVERROR_INVALIDDATA;

    }

    if (!h->setup_finished) {

        h->ps.pps = (const PPS*)h->ps.pps_list[pps_id]->data;

    } else if (h->ps.pps != (const PPS*)h->ps.pps_list[pps_id]->data) {

        av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n");

        return AVERROR_INVALIDDATA;

    }

    if (!h->ps.sps_list[h->ps.pps->sps_id]) {

        av_log(h->avctx, AV_LOG_ERROR,

               "non-existing SPS %u referenced\n",

               h->ps.pps->sps_id);

        return AVERROR_INVALIDDATA;

    }

    if (h->ps.sps != (const SPS*)h->ps.sps_list[h->ps.pps->sps_id]->data) {

        h->ps.sps = (SPS*)h->ps.sps_list[h->ps.pps->sps_id]->data;

        if (h->bit_depth_luma    != h->ps.sps->bit_depth_luma ||

            h->chroma_format_idc != h->ps.sps->chroma_format_idc)

            needs_reinit         = 1;

        if (h->flags & AV_CODEC_FLAG_LOW_DELAY ||

            (h->ps.sps->bitstream_restriction_flag &&

             !h->ps.sps->num_reorder_frames)) {

            if (h->avctx->has_b_frames > 1 || h->delayed_pic[0])

                av_log(h->avctx, AV_LOG_WARNING, "Delayed frames seen. "

                       "Reenabling low delay requires a codec flush.\n");

            else

                h->low_delay = 1;

        }

        if (h->avctx->has_b_frames < 2)

            h->avctx->has_b_frames = !h->low_delay;

    }

    pps = h->ps.pps;

    sps = h->ps.sps;

    if (!h->setup_finished) {

        h->avctx->profile = ff_h264_get_profile(sps);

        h->avctx->level   = sps->level_idc;

        h->avctx->refs    = sps->ref_frame_count;

        if (h->mb_width  != sps->mb_width ||

            h->mb_height != sps->mb_height * (2 - sps->frame_mbs_only_flag))

            needs_reinit = 1;

        h->mb_width  = sps->mb_width;

        h->mb_height = sps->mb_height * (2 - sps->frame_mbs_only_flag);

        h->mb_num    = h->mb_width * h->mb_height;

        h->mb_stride = h->mb_width + 1;

        h->b_stride = h->mb_width * 4;

        h->chroma_y_shift = sps->chroma_format_idc <= 1; // 400 uses yuv420p

        h->width  = 16 * h->mb_width;

        h->height = 16 * h->mb_height;

        ret = init_dimensions(h);

        if (ret < 0)

            return ret;

        if (sps->video_signal_type_present_flag) {

            h->avctx->color_range = sps->full_range ? AVCOL_RANGE_JPEG

                : AVCOL_RANGE_MPEG;

            if (sps->colour_description_present_flag) {

                if (h->avctx->colorspace != sps->colorspace)

                    needs_reinit = 1;

                h->avctx->color_primaries = sps->color_primaries;

                h->avctx->color_trc       = sps->color_trc;

                h->avctx->colorspace      = sps->colorspace;

            }

        }

    }

    if (h->context_initialized && needs_reinit) {

        h->context_initialized = 0;

        if (sl != h->slice_ctx) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "changing width %d -> %d / height %d -> %d on "

                   "slice %d\n",

                   h->width, h->avctx->coded_width,

                   h->height, h->avctx->coded_height,

                   h->current_slice + 1);

            return AVERROR_INVALIDDATA;

        }

        ff_h264_flush_change(h);

        if ((ret = get_pixel_format(h)) < 0)

            return ret;

        h->avctx->pix_fmt = ret;

        av_log(h->avctx, AV_LOG_INFO, "Reinit context to %dx%d, "

               "pix_fmt: %d\n", h->width, h->height, h->avctx->pix_fmt);

        if ((ret = h264_slice_header_init(h)) < 0) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "h264_slice_header_init() failed\n");

            return ret;

        }

    }

    if (!h->context_initialized) {

        if (sl != h->slice_ctx) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "Cannot (re-)initialize context during parallel decoding.\n");

            return AVERROR_PATCHWELCOME;

        }

        if ((ret = get_pixel_format(h)) < 0)

            return ret;

        h->avctx->pix_fmt = ret;

        if ((ret = h264_slice_header_init(h)) < 0) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "h264_slice_header_init() failed\n");

            return ret;

        }

    }

    frame_num = get_bits(&sl->gb, sps->log2_max_frame_num);

    if (!h->setup_finished)

        h->frame_num = frame_num;

    sl->mb_mbaff       = 0;

    last_pic_structure = h->picture_structure;

    last_pic_droppable = h->droppable;

    droppable = h->nal_ref_idc == 0;

    if (sps->frame_mbs_only_flag) {

        picture_structure = PICT_FRAME;

    } else {

        field_pic_flag = get_bits1(&sl->gb);

        if (field_pic_flag) {

            bottom_field_flag = get_bits1(&sl->gb);

            picture_structure = PICT_TOP_FIELD + bottom_field_flag;

        } else {

            picture_structure = PICT_FRAME;

            mb_aff_frame      = sps->mb_aff;

        }

    }

    if (!h->setup_finished) {

        h->droppable         = droppable;

        h->picture_structure = picture_structure;

        h->mb_aff_frame      = mb_aff_frame;

    }

    sl->mb_field_decoding_flag = h->picture_structure != PICT_FRAME;

    if (h->current_slice != 0) {

        if (last_pic_structure != picture_structure ||

            last_pic_droppable != droppable) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "Changing field mode (%d -> %d) between slices is not allowed\n",

                   last_pic_structure, h->picture_structure);

            return AVERROR_INVALIDDATA;

        } else if (!h->cur_pic_ptr) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "unset cur_pic_ptr on slice %d\n",

                   h->current_slice + 1);

            return AVERROR_INVALIDDATA;

        }

    } else {

        /* Shorten frame num gaps so we don't have to allocate reference

         * frames just to throw them away */

        if (h->frame_num != h->prev_frame_num) {

            int unwrap_prev_frame_num = h->prev_frame_num;

            int max_frame_num         = 1 << sps->log2_max_frame_num;

            if (unwrap_prev_frame_num > h->frame_num)

                unwrap_prev_frame_num -= max_frame_num;

            if ((h->frame_num - unwrap_prev_frame_num) > sps->ref_frame_count) {

                unwrap_prev_frame_num = (h->frame_num - sps->ref_frame_count) - 1;

                if (unwrap_prev_frame_num < 0)

                    unwrap_prev_frame_num += max_frame_num;

                h->prev_frame_num = unwrap_prev_frame_num;

            }

        }

        /* See if we have a decoded first field looking for a pair...

         * Here, we're using that to see if we should mark previously

         * decode frames as "finished".

         * We have to do that before the "dummy" in-between frame allocation,

         * since that can modify s->current_picture_ptr. */

        if (h->first_field) {

            assert(h->cur_pic_ptr);

            assert(h->cur_pic_ptr->f->buf[0]);

            assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF);

            /* figure out if we have a complementary field pair */

            if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) {

                /* Previous field is unmatched. Don't display it, but let it

                 * remain for reference if marked as such. */

                if (!last_pic_droppable && last_pic_structure != PICT_FRAME) {

                    ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,

                                              last_pic_structure == PICT_TOP_FIELD);

                }

            } else {

                if (h->cur_pic_ptr->frame_num != h->frame_num) {

                    /* This and previous field were reference, but had

                     * different frame_nums. Consider this field first in

                     * pair. Throw away previous field except for reference

                     * purposes. */

                    if (!last_pic_droppable && last_pic_structure != PICT_FRAME) {

                        ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,

                                                  last_pic_structure == PICT_TOP_FIELD);

                    }

                } else {

                    /* Second field in complementary pair */

                    if (!((last_pic_structure   == PICT_TOP_FIELD &&

                           h->picture_structure == PICT_BOTTOM_FIELD) ||

                          (last_pic_structure   == PICT_BOTTOM_FIELD &&

                           h->picture_structure == PICT_TOP_FIELD))) {

                        av_log(h->avctx, AV_LOG_ERROR,

                               "Invalid field mode combination %d/%d\n",

                               last_pic_structure, h->picture_structure);

                        h->picture_structure = last_pic_structure;

                        h->droppable         = last_pic_droppable;

                        return AVERROR_INVALIDDATA;

                    } else if (last_pic_droppable != h->droppable) {

                        avpriv_request_sample(h->avctx,

                                              "Found reference and non-reference fields in the same frame, which");

                        h->picture_structure = last_pic_structure;

                        h->droppable         = last_pic_droppable;

                        return AVERROR_PATCHWELCOME;

                    }

                }

            }

        }

        while (h->frame_num != h->prev_frame_num &&

               h->frame_num != (h->prev_frame_num + 1) % (1 << sps->log2_max_frame_num)) {

            H264Picture *prev = h->short_ref_count ? h->short_ref[0] : NULL;

            av_log(h->avctx, AV_LOG_DEBUG, "Frame num gap %d %d\n",

                   h->frame_num, h->prev_frame_num);

            ret = initialize_cur_frame(h);

            if (ret < 0) {

                h->first_field = 0;

                return ret;

            }

            h->prev_frame_num++;

            h->prev_frame_num        %= 1 << sps->log2_max_frame_num;

            h->cur_pic_ptr->frame_num = h->prev_frame_num;

            ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0);

            ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1);

            ret = ff_generate_sliding_window_mmcos(h, 1);

            if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))

                return ret;

            ret = ff_h264_execute_ref_pic_marking(h, h->mmco, h->mmco_index);

            if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))

                return ret;

            /* Error concealment: If a ref is missing, copy the previous ref

             * in its place.

             * FIXME: Avoiding a memcpy would be nice, but ref handling makes

             * many assumptions about there being no actual duplicates.

             * FIXME: This does not copy padding for out-of-frame motion

             * vectors.  Given we are concealing a lost frame, this probably

             * is not noticeable by comparison, but it should be fixed. */

            if (h->short_ref_count) {

                if (prev &&

                    h->short_ref[0]->f->width == prev->f->width &&

                    h->short_ref[0]->f->height == prev->f->height &&

                    h->short_ref[0]->f->format == prev->f->format) {

                    av_image_copy(h->short_ref[0]->f->data,

                                  h->short_ref[0]->f->linesize,

                                  (const uint8_t **)prev->f->data,

                                  prev->f->linesize,

                                  prev->f->format,

                                  h->mb_width  * 16,

                                  h->mb_height * 16);

                    h->short_ref[0]->poc = prev->poc + 2;

                }

                h->short_ref[0]->frame_num = h->prev_frame_num;

            }

        }

        /* See if we have a decoded first field looking for a pair...

         * We're using that to see whether to continue decoding in that

         * frame, or to allocate a new one. */

        if (h->first_field) {

            assert(h->cur_pic_ptr);

            assert(h->cur_pic_ptr->f->buf[0]);

            assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF);

            /* figure out if we have a complementary field pair */

            if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) {

                /* Previous field is unmatched. Don't display it, but let it

                 * remain for reference if marked as such. */

                h->cur_pic_ptr = NULL;

                h->first_field = FIELD_PICTURE(h);

            } else {

                if (h->cur_pic_ptr->frame_num != h->frame_num) {

                    /* This and the previous field had different frame_nums.

                     * Consider this field first in pair. Throw away previous

                     * one except for reference purposes. */

                    h->first_field = 1;

                    h->cur_pic_ptr = NULL;

                } else {

                    /* Second field in complementary pair */

                    h->first_field = 0;

                }

            }

        } else {

            /* Frame or first field in a potentially complementary pair */

            h->first_field = FIELD_PICTURE(h);

        }

        if (!FIELD_PICTURE(h) || h->first_field) {

            if (h264_frame_start(h) < 0) {

                h->first_field = 0;

                return AVERROR_INVALIDDATA;

            }

        } else {

            release_unused_pictures(h, 0);

        }

    }

    assert(h->mb_num == h->mb_width * h->mb_height);

    if (first_mb_in_slice << FIELD_OR_MBAFF_PICTURE(h) >= h->mb_num ||

        first_mb_in_slice >= h->mb_num) {

        av_log(h->avctx, AV_LOG_ERROR, "first_mb_in_slice overflow\n");

        return AVERROR_INVALIDDATA;

    }

    sl->resync_mb_x = sl->mb_x =  first_mb_in_slice % h->mb_width;

    sl->resync_mb_y = sl->mb_y = (first_mb_in_slice / h->mb_width) <<

                                 FIELD_OR_MBAFF_PICTURE(h);

    if (h->picture_structure == PICT_BOTTOM_FIELD)

        sl->resync_mb_y = sl->mb_y = sl->mb_y + 1;

    assert(sl->mb_y < h->mb_height);

    if (h->picture_structure == PICT_FRAME) {

        h->curr_pic_num = h->frame_num;

        h->max_pic_num  = 1 << sps->log2_max_frame_num;

    } else {

        h->curr_pic_num = 2 * h->frame_num + 1;

        h->max_pic_num  = 1 << (sps->log2_max_frame_num + 1);

    }

    if (h->nal_unit_type == NAL_IDR_SLICE)

        get_ue_golomb(&sl->gb); /* idr_pic_id */

    if (sps->poc_type == 0) {

        int poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb);

        if (!h->setup_finished)

            h->poc_lsb = poc_lsb;

        if (pps->pic_order_present == 1 && h->picture_structure == PICT_FRAME) {

            int delta_poc_bottom = get_se_golomb(&sl->gb);

            if (!h->setup_finished)

                h->delta_poc_bottom = delta_poc_bottom;

        }

    }

    if (sps->poc_type == 1 && !sps->delta_pic_order_always_zero_flag) {

        int delta_poc = get_se_golomb(&sl->gb);

        if (!h->setup_finished)

            h->delta_poc[0] = delta_poc;

        if (pps->pic_order_present == 1 && h->picture_structure == PICT_FRAME) {

            delta_poc = get_se_golomb(&sl->gb);

            if (!h->setup_finished)

                h->delta_poc[1] = delta_poc;

        }

    }

    if (!h->setup_finished)

        ff_init_poc(h, h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc);

    if (pps->redundant_pic_cnt_present)

        sl->redundant_pic_count = get_ue_golomb(&sl->gb);

    if (sl->slice_type_nos == AV_PICTURE_TYPE_B)

        sl->direct_spatial_mv_pred = get_bits1(&sl->gb);

    ret = ff_h264_parse_ref_count(&sl->list_count, sl->ref_count,

                                  &sl->gb, pps, sl->slice_type_nos,

                                  h->picture_structure);

    if (ret < 0)

        return ret;

    if (sl->slice_type_nos != AV_PICTURE_TYPE_I) {

       ret = ff_h264_decode_ref_pic_list_reordering(h, sl);

       if (ret < 0) {

           sl->ref_count[1] = sl->ref_count[0] = 0;

           return ret;

       }

    }

    if ((pps->weighted_pred && sl->slice_type_nos == AV_PICTURE_TYPE_P) ||

        (pps->weighted_bipred_idc == 1 &&

         sl->slice_type_nos == AV_PICTURE_TYPE_B))

        ff_h264_pred_weight_table(&sl->gb, sps, sl->ref_count,

                                  sl->slice_type_nos, &sl->pwt);

    else if (pps->weighted_bipred_idc == 2 &&

             sl->slice_type_nos == AV_PICTURE_TYPE_B) {

        implicit_weight_table(h, sl, -1);

    } else {

        sl->pwt.use_weight = 0;

        for (i = 0; i < 2; i++) {

            sl->pwt.luma_weight_flag[i]   = 0;

            sl->pwt.chroma_weight_flag[i] = 0;

        }

    }

    // If frame-mt is enabled, only update mmco tables for the first slice

    // in a field. Subsequent slices can temporarily clobber h->mmco_index

    // or h->mmco, which will cause ref list mix-ups and decoding errors

    // further down the line. This may break decoding if the first slice is

    // corrupt, thus we only do this if frame-mt is enabled.

    if (h->nal_ref_idc) {

        ret = ff_h264_decode_ref_pic_marking(h, &sl->gb,

                                             !(h->avctx->active_thread_type & FF_THREAD_FRAME) ||

                                             h->current_slice == 0);

        if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))

            return AVERROR_INVALIDDATA;

    }

    if (FRAME_MBAFF(h)) {

        ff_h264_fill_mbaff_ref_list(h, sl);

        if (pps->weighted_bipred_idc == 2 && sl->slice_type_nos == AV_PICTURE_TYPE_B) {

            implicit_weight_table(h, sl, 0);

            implicit_weight_table(h, sl, 1);

        }

    }

    if (sl->slice_type_nos == AV_PICTURE_TYPE_B && !sl->direct_spatial_mv_pred)

        ff_h264_direct_dist_scale_factor(h, sl);

    ff_h264_direct_ref_list_init(h, sl);

    if (sl->slice_type_nos != AV_PICTURE_TYPE_I && pps->cabac) {

        tmp = get_ue_golomb_31(&sl->gb);

        if (tmp > 2) {

            av_log(h->avctx, AV_LOG_ERROR, "cabac_init_idc %u overflow\n", tmp);

            return AVERROR_INVALIDDATA;

        }

        sl->cabac_init_idc = tmp;

    }

    sl->last_qscale_diff = 0;

    tmp = pps->init_qp + get_se_golomb(&sl->gb);

    if (tmp > 51 + 6 * (sps->bit_depth_luma - 8)) {

        av_log(h->avctx, AV_LOG_ERROR, "QP %u out of range\n", tmp);

        return AVERROR_INVALIDDATA;

    }

    sl->qscale       = tmp;

    sl->chroma_qp[0] = get_chroma_qp(h, 0, sl->qscale);

    sl->chroma_qp[1] = get_chroma_qp(h, 1, sl->qscale);

    // FIXME qscale / qp ... stuff

    if (sl->slice_type == AV_PICTURE_TYPE_SP)

        get_bits1(&sl->gb); /* sp_for_switch_flag */

    if (sl->slice_type == AV_PICTURE_TYPE_SP ||

        sl->slice_type == AV_PICTURE_TYPE_SI)

        get_se_golomb(&sl->gb); /* slice_qs_delta */

    sl->deblocking_filter     = 1;

    sl->slice_alpha_c0_offset = 0;

    sl->slice_beta_offset     = 0;

    if (pps->deblocking_filter_parameters_present) {

        tmp = get_ue_golomb_31(&sl->gb);

        if (tmp > 2) {

            av_log(h->avctx, AV_LOG_ERROR,

                   "deblocking_filter_idc %u out of range\n", tmp);

            return AVERROR_INVALIDDATA;

        }

        sl->deblocking_filter = tmp;

        if (sl->deblocking_filter < 2)

            sl->deblocking_filter ^= 1;  // 1<->0

        if (sl->deblocking_filter) {

            sl->slice_alpha_c0_offset = get_se_golomb(&sl->gb) * 2;

            sl->slice_beta_offset     = get_se_golomb(&sl->gb) * 2;

            if (sl->slice_alpha_c0_offset >  12 ||

                sl->slice_alpha_c0_offset < -12 ||

                sl->slice_beta_offset >  12     ||

                sl->slice_beta_offset < -12) {

                av_log(h->avctx, AV_LOG_ERROR,

                       "deblocking filter parameters %d %d out of range\n",

                       sl->slice_alpha_c0_offset, sl->slice_beta_offset);

                return AVERROR_INVALIDDATA;

            }

        }

    }

    if (h->avctx->skip_loop_filter >= AVDISCARD_ALL ||

        (h->avctx->skip_loop_filter >= AVDISCARD_NONKEY &&

         sl->slice_type_nos != AV_PICTURE_TYPE_I) ||

        (h->avctx->skip_loop_filter >= AVDISCARD_BIDIR  &&

         sl->slice_type_nos == AV_PICTURE_TYPE_B) ||

        (h->avctx->skip_loop_filter >= AVDISCARD_NONREF &&

         h->nal_ref_idc == 0))

        sl->deblocking_filter = 0;

    if (sl->deblocking_filter == 1 && h->max_contexts > 1) {

        if (h->avctx->flags2 & AV_CODEC_FLAG2_FAST) {

            /* Cheat slightly for speed:

             * Do not bother to deblock across slices. */

            sl->deblocking_filter = 2;

        } else {

            h->max_contexts = 1;

            if (!h->single_decode_warning) {

                av_log(h->avctx, AV_LOG_INFO,

                       "Cannot parallelize deblocking type 1, decoding such frames in sequential order\n");

                h->single_decode_warning = 1;

            }

            if (sl != h->slice_ctx) {

                av_log(h->avctx, AV_LOG_ERROR,

                       "Deblocking switched inside frame.\n");

                return 1;

            }

        }

    }

    sl->qp_thresh = 15 -

                   FFMIN(sl->slice_alpha_c0_offset, sl->slice_beta_offset) -

                   FFMAX3(0,

                          pps->chroma_qp_index_offset[0],

                          pps->chroma_qp_index_offset[1]) +

                   6 * (sps->bit_depth_luma - 8);

    sl->slice_num       = ++h->current_slice;

    if (sl->slice_num >= MAX_SLICES) {

        av_log(h->avctx, AV_LOG_ERROR,

               "Too many slices, increase MAX_SLICES and recompile\n");

    }

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

        int id_list[16];

        int *ref2frm = sl->ref2frm[sl->slice_num & (MAX_SLICES - 1)][j];

        for (i = 0; i < 16; i++) {

            id_list[i] = 60;

            if (j < sl->list_count && i < sl->ref_count[j] &&

                sl->ref_list[j][i].parent->f->buf[0]) {

                int k;

                AVBuffer *buf = sl->ref_list[j][i].parent->f->buf[0]->buffer;

                for (k = 0; k < h->short_ref_count; k++)

                    if (h->short_ref[k]->f->buf[0]->buffer == buf) {

                        id_list[i] = k;

                        break;

                    }

                for (k = 0; k < h->long_ref_count; k++)

                    if (h->long_ref[k] && h->long_ref[k]->f->buf[0]->buffer == buf) {

                        id_list[i] = h->short_ref_count + k;

                        break;

                    }

            }

        }

        ref2frm[0] =

        ref2frm[1] = -1;

        for (i = 0; i < 16; i++)

            ref2frm[i + 2] = 4 * id_list[i] + (sl->ref_list[j][i].reference & 3);

        ref2frm[18 + 0] =

        ref2frm[18 + 1] = -1;

        for (i = 16; i < 48; i++)

            ref2frm[i + 4] = 4 * id_list[(i - 16) >> 1] +

                             (sl->ref_list[j][i].reference & 3);

    }

    if (h->avctx->debug & FF_DEBUG_PICT_INFO) {

        av_log(h->avctx, AV_LOG_DEBUG,

               "slice:%d %s mb:%d %c%s%s pps:%u frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d:%d:%d weight:%d%s %s\n",

               sl->slice_num,

               (h->picture_structure == PICT_FRAME ? "F" : h->picture_structure == PICT_TOP_FIELD ? "T" : "B"),

               first_mb_in_slice,

               av_get_picture_type_char(sl->slice_type),

               sl->slice_type_fixed ? " fix" : "",

               h->nal_unit_type == NAL_IDR_SLICE ? " IDR" : "",

               pps_id, h->frame_num,

               h->cur_pic_ptr->field_poc[0],

               h->cur_pic_ptr->field_poc[1],

               sl->ref_count[0], sl->ref_count[1],

               sl->qscale,

               sl->deblocking_filter,

               sl->slice_alpha_c0_offset, sl->slice_beta_offset,

               sl->pwt.use_weight,

               sl->pwt.use_weight == 1 && sl->pwt.use_weight_chroma ? "c" : "",

               sl->slice_type == AV_PICTURE_TYPE_B ? (sl->direct_spatial_mv_pred ? "SPAT" : "TEMP") : "");

    }

    return 0;

}


void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)

{

    uint32_t type;

    struct iovec *in_iov = req->elem.in_sg;

    struct iovec *iov = req->elem.out_sg;

    unsigned in_num = req->elem.in_num;

    unsigned out_num = req->elem.out_num;

    if (req->elem.out_num < 1 || req->elem.in_num < 1) {

        error_report("virtio-blk missing headers");

        exit(1);

    }

    if (unlikely(iov_to_buf(iov, out_num, 0, &req->out,

                            sizeof(req->out)) != sizeof(req->out))) {

        error_report("virtio-blk request outhdr too short");

        exit(1);

    }

    iov_discard_front(&iov, &out_num, sizeof(req->out));

    if (in_num < 1 ||

        in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {

        error_report("virtio-blk request inhdr too short");

        exit(1);

    }

    /* We always touch the last byte, so just see how big in_iov is.  */

    req->in_len = iov_size(in_iov, in_num);

    req->in = (void *)in_iov[in_num - 1].iov_base

              + in_iov[in_num - 1].iov_len

              - sizeof(struct virtio_blk_inhdr);

    iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));

    type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);

    /* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER

     * is an optional flag. Although a guest should not send this flag if

     * not negotiated we ignored it in the past. So keep ignoring it. */

    switch (type & ~(VIRTIO_BLK_T_OUT | VIRTIO_BLK_T_BARRIER)) {

    case VIRTIO_BLK_T_IN:

    {

        bool is_write = type & VIRTIO_BLK_T_OUT;

        req->sector_num = virtio_ldq_p(VIRTIO_DEVICE(req->dev),

                                       &req->out.sector);

        if (is_write) {

            qemu_iovec_init_external(&req->qiov, iov, out_num);

            trace_virtio_blk_handle_write(req, req->sector_num,

                                          req->qiov.size / BDRV_SECTOR_SIZE);

        } else {

            qemu_iovec_init_external(&req->qiov, in_iov, in_num);

            trace_virtio_blk_handle_read(req, req->sector_num,

                                         req->qiov.size / BDRV_SECTOR_SIZE);

        }

        if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,

                                      req->qiov.size)) {

            virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);

            virtio_blk_free_request(req);

            return;

        }

        block_acct_start(blk_get_stats(req->dev->blk),

                         &req->acct, req->qiov.size,

                         is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);

        /* merge would exceed maximum number of requests or IO direction

         * changes */

        if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS ||

                                  is_write != mrb->is_write ||

                                  !req->dev->conf.request_merging)) {

            virtio_blk_submit_multireq(req->dev->blk, mrb);

        }

        assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS);

        mrb->reqs[mrb->num_reqs++] = req;

        mrb->is_write = is_write;

        break;

    }

    case VIRTIO_BLK_T_FLUSH:

        virtio_blk_handle_flush(req, mrb);

        break;

    case VIRTIO_BLK_T_SCSI_CMD:

        virtio_blk_handle_scsi(req);

        break;

    case VIRTIO_BLK_T_GET_ID:

    {

        VirtIOBlock *s = req->dev;

        /*

         * NB: per existing s/n string convention the string is

         * terminated by '\0' only when shorter than buffer.

         */

        const char *serial = s->conf.serial ? s->conf.serial : "";

        size_t size = MIN(strlen(serial) + 1,

                          MIN(iov_size(in_iov, in_num),

                              VIRTIO_BLK_ID_BYTES));

        iov_from_buf(in_iov, in_num, 0, serial, size);

        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);

        virtio_blk_free_request(req);

        break;

    }

    default:

        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);

        virtio_blk_free_request(req);

    }

}


static void net_vhost_user_event(void *opaque, int event)

{

    VhostUserState *s = opaque;

    switch (event) {

    case CHR_EVENT_OPENED:

        vhost_user_start(s);

        net_vhost_link_down(s, false);

        error_report("chardev \"%s\" went up", s->chr->label);

        break;

    case CHR_EVENT_CLOSED:

        net_vhost_link_down(s, true);

        vhost_user_stop(s);

        error_report("chardev \"%s\" went down", s->chr->label);

        break;

    }

}


static uint32_t virtio_blk_get_features(VirtIODevice *vdev)

{

    VirtIOBlock *s = to_virtio_blk(vdev);

    uint32_t features = 0;

    features |= (1 << VIRTIO_BLK_F_SEG_MAX);

    features |= (1 << VIRTIO_BLK_F_GEOMETRY);

    if (bdrv_enable_write_cache(s->bs))

        features |= (1 << VIRTIO_BLK_F_WCACHE);

#ifdef __linux__

    features |= (1 << VIRTIO_BLK_F_SCSI);

#endif

    if (strcmp(s->serial_str, "0"))

        features |= 1 << VIRTIO_BLK_F_IDENTIFY;

    if (bdrv_is_read_only(s->bs))

        features |= 1 << VIRTIO_BLK_F_RO;

    return features;

}


static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)

{

    printf("%s: what are we supposed to do with (%08x)?\n",

                    __FUNCTION__, data);

}


static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)

{

    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);

    register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);

    register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);

}


static void qemu_chr_fire_open_event(void *opaque)

{

    CharDriverState *s = opaque;

    qemu_chr_be_event(s, CHR_EVENT_OPENED);

    qemu_free_timer(s->open_timer);

    s->open_timer = NULL;

}


static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)

{

    BDRVSheepdogState *s = bs->opaque;

    BDRVSheepdogState *old_s;

    char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];

    char *buf = NULL;

    uint32_t vid;

    uint32_t snapid = 0;

    int ret = 0, fd;

    old_s = g_malloc(sizeof(BDRVSheepdogState));

    memcpy(old_s, s, sizeof(BDRVSheepdogState));

    pstrcpy(vdi, sizeof(vdi), s->name);

    snapid = strtoul(snapshot_id, NULL, 10);

    if (snapid) {

        tag[0] = 0;

    } else {

        pstrcpy(tag, sizeof(tag), s->name);

    }

    ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);

    if (ret) {

        error_report("Failed to find_vdi_name");

        goto out;

    }

    fd = connect_to_sdog(s->addr, s->port);

    if (fd < 0) {

        error_report("failed to connect");

        ret = fd;

        goto out;

    }

    buf = g_malloc(SD_INODE_SIZE);

    ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,

                      SD_INODE_SIZE, 0, s->cache_enabled);

    closesocket(fd);

    if (ret) {

        goto out;

    }

    memcpy(&s->inode, buf, sizeof(s->inode));

    if (!s->inode.vm_state_size) {

        error_report("Invalid snapshot");

        ret = -ENOENT;

        goto out;

    }

    s->is_snapshot = true;

    g_free(buf);

    g_free(old_s);

    return 0;

out:

    /* recover bdrv_sd_state */

    memcpy(s, old_s, sizeof(BDRVSheepdogState));

    g_free(buf);

    g_free(old_s);

    error_report("failed to open. recover old bdrv_sd_state.");

    return ret;

}


static void ehci_advance_state(EHCIState *ehci,

                               int async)

{

    EHCIQueue *q = NULL;

    int again;

    int iter = 0;

    do {

        if (ehci_get_state(ehci, async) == EST_FETCHQH) {

            iter++;

            /* if we are roaming a lot of QH without executing a qTD

             * something is wrong with the linked list. TO-DO: why is

             * this hack needed?

             */

            assert(iter < MAX_ITERATIONS);

#if 0

            if (iter > MAX_ITERATIONS) {

                DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");

                ehci_set_state(ehci, async, EST_ACTIVE);

                break;

            }

#endif

        }

        switch(ehci_get_state(ehci, async)) {

        case EST_WAITLISTHEAD:

            again = ehci_state_waitlisthead(ehci, async);

            break;

        case EST_FETCHENTRY:

            again = ehci_state_fetchentry(ehci, async);

            break;

        case EST_FETCHQH:

            q = ehci_state_fetchqh(ehci, async);

            again = q ? 1 : 0;

            break;

        case EST_FETCHITD:

            again = ehci_state_fetchitd(ehci, async);

            break;

        case EST_FETCHSITD:

            again = ehci_state_fetchsitd(ehci, async);

            break;

        case EST_ADVANCEQUEUE:

            again = ehci_state_advqueue(q, async);

            break;

        case EST_FETCHQTD:

            again = ehci_state_fetchqtd(q, async);

            break;

        case EST_HORIZONTALQH:

            again = ehci_state_horizqh(q, async);

            break;

        case EST_EXECUTE:

            iter = 0;

            again = ehci_state_execute(q, async);

            break;

        case EST_EXECUTING:

            assert(q != NULL);

            again = ehci_state_executing(q, async);

            break;

        case EST_WRITEBACK:

            assert(q != NULL);

            again = ehci_state_writeback(q, async);

            break;

        default:

            fprintf(stderr, "Bad state!\n");

            again = -1;

            assert(0);

            break;

        }

        if (again < 0) {

            fprintf(stderr, "processing error - resetting ehci HC\n");

            ehci_reset(ehci);

            again = 0;

        }

    }

    while (again);

    ehci_commit_interrupt(ehci);

}


static av_always_inline void mpeg_motion_lowres(MpegEncContext *s,

                                                uint8_t *dest_y,

                                                uint8_t *dest_cb,

                                                uint8_t *dest_cr,

                                                int field_based,

                                                int bottom_field,

                                                int field_select,

                                                uint8_t **ref_picture,

                                                h264_chroma_mc_func *pix_op,

                                                int motion_x, int motion_y,

                                                int h, int mb_y)

{

    uint8_t *ptr_y, *ptr_cb, *ptr_cr;

    int mx, my, src_x, src_y, uvsrc_x, uvsrc_y, uvlinesize, linesize, sx, sy,

        uvsx, uvsy;

    const int lowres     = s->avctx->lowres;

    const int op_index   = FFMIN(lowres-1+s->chroma_x_shift, 2);

    const int block_s    = 8>>lowres;

    const int s_mask     = (2 << lowres) - 1;

    const int h_edge_pos = s->h_edge_pos >> lowres;

    const int v_edge_pos = s->v_edge_pos >> lowres;

    linesize   = s->current_picture.f.linesize[0] << field_based;

    uvlinesize = s->current_picture.f.linesize[1] << field_based;

    // FIXME obviously not perfect but qpel will not work in lowres anyway

    if (s->quarter_sample) {

        motion_x /= 2;

        motion_y /= 2;

    }

    if(field_based){

        motion_y += (bottom_field - field_select)*((1 << lowres)-1);

    }

    sx = motion_x & s_mask;

    sy = motion_y & s_mask;

    src_x = s->mb_x * 2 * block_s + (motion_x >> lowres + 1);

    src_y = (mb_y * 2 * block_s >> field_based) + (motion_y >> lowres + 1);

    if (s->out_format == FMT_H263) {

        uvsx    = ((motion_x >> 1) & s_mask) | (sx & 1);

        uvsy    = ((motion_y >> 1) & s_mask) | (sy & 1);

        uvsrc_x = src_x >> 1;

        uvsrc_y = src_y >> 1;

    } else if (s->out_format == FMT_H261) {

        // even chroma mv's are full pel in H261

        mx      = motion_x / 4;

        my      = motion_y / 4;

        uvsx    = (2 * mx) & s_mask;

        uvsy    = (2 * my) & s_mask;

        uvsrc_x = s->mb_x * block_s + (mx >> lowres);

        uvsrc_y =    mb_y * block_s + (my >> lowres);

    } else {

        if(s->chroma_y_shift){

            mx      = motion_x / 2;

            my      = motion_y / 2;

            uvsx    = mx & s_mask;

            uvsy    = my & s_mask;

            uvsrc_x = s->mb_x * block_s                 + (mx >> lowres + 1);

            uvsrc_y =   (mb_y * block_s >> field_based) + (my >> lowres + 1);

        } else {

            if(s->chroma_x_shift){

            //Chroma422

                mx = motion_x / 2;

                uvsx = mx & s_mask;

                uvsy = motion_y & s_mask;

                uvsrc_y = src_y;

                uvsrc_x = s->mb_x*block_s               + (mx >> (lowres+1));

            } else {

            //Chroma444

                uvsx = motion_x & s_mask;

                uvsy = motion_y & s_mask;

                uvsrc_x = src_x;

                uvsrc_y = src_y;

            }

        }

    }

    ptr_y  = ref_picture[0] + src_y   * linesize   + src_x;

    ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;

    ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;

    if ((unsigned) src_x > FFMAX( h_edge_pos - (!!sx) - 2 * block_s,       0) || uvsrc_y<0 ||

        (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) {

        s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,

                                linesize >> field_based, 17, 17 + field_based,

                                src_x, src_y << field_based, h_edge_pos,

                                v_edge_pos);

        ptr_y = s->edge_emu_buffer;

        if (!CONFIG_GRAY || !(s->flags & CODEC_FLAG_GRAY)) {

            uint8_t *uvbuf = s->edge_emu_buffer + 18 * s->linesize;

            s->vdsp.emulated_edge_mc(uvbuf , ptr_cb, uvlinesize >> field_based, 9,

                                    9 + field_based,

                                    uvsrc_x, uvsrc_y << field_based,

                                    h_edge_pos >> 1, v_edge_pos >> 1);

            s->vdsp.emulated_edge_mc(uvbuf + 16, ptr_cr, uvlinesize >> field_based, 9,

                                    9 + field_based,

                                    uvsrc_x, uvsrc_y << field_based,

                                    h_edge_pos >> 1, v_edge_pos >> 1);

            ptr_cb = uvbuf;

            ptr_cr = uvbuf + 16;

        }

    }

    // FIXME use this for field pix too instead of the obnoxious hack which changes picture.f.data

    if (bottom_field) {

        dest_y  += s->linesize;

        dest_cb += s->uvlinesize;

        dest_cr += s->uvlinesize;

    }

    if (field_select) {

        ptr_y   += s->linesize;

        ptr_cb  += s->uvlinesize;

        ptr_cr  += s->uvlinesize;

    }

    sx = (sx << 2) >> lowres;

    sy = (sy << 2) >> lowres;

    pix_op[lowres - 1](dest_y, ptr_y, linesize, h, sx, sy);

    if (!CONFIG_GRAY || !(s->flags & CODEC_FLAG_GRAY)) {

        int hc = s->chroma_y_shift ? (h+1-bottom_field)>>1 : h;

        uvsx = (uvsx << 2) >> lowres;

        uvsy = (uvsy << 2) >> lowres;

        if (hc) {

            pix_op[op_index](dest_cb, ptr_cb, uvlinesize, hc, uvsx, uvsy);

            pix_op[op_index](dest_cr, ptr_cr, uvlinesize, hc, uvsx, uvsy);

        }

    }

    // FIXME h261 lowres loop filter

}


static bool run_poll_handlers_once(AioContext *ctx)

{

    bool progress = false;

    AioHandler *node;

    QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) {

        if (!node->deleted && node->io_poll &&

            aio_node_check(ctx, node->is_external) &&

            node->io_poll(node->opaque)) {

            progress = true;

        }

        /* Caller handles freeing deleted nodes.  Don't do it here. */

    }

    return progress;

}


print_insn_ppi (int field_b, struct disassemble_info *info)

{

  static const char *sx_tab[] = { "x0", "x1", "a0", "a1" };

  static const char *sy_tab[] = { "y0", "y1", "m0", "m1" };

  fprintf_ftype fprintf_fn = info->fprintf_func;

  void *stream = info->stream;

  unsigned int nib1, nib2, nib3;

  unsigned int altnib1, nib4;

  const char *dc = NULL;

  const sh_opcode_info *op;

  if ((field_b & 0xe800) == 0)

    {

      fprintf_fn (stream, "psh%c\t#%d,",

		  field_b & 0x1000 ? 'a' : 'l',

		  (field_b >> 4) & 127);

      print_dsp_reg (field_b & 0xf, fprintf_fn, stream);

      return;

    }

  if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)

    {

      static const char *du_tab[] = { "x0", "y0", "a0", "a1" };

      static const char *se_tab[] = { "x0", "x1", "y0", "a1" };

      static const char *sf_tab[] = { "y0", "y1", "x0", "a1" };

      static const char *sg_tab[] = { "m0", "m1", "a0", "a1" };

      if (field_b & 0x2000)

	{

	  fprintf_fn (stream, "p%s %s,%s,%s\t",

		      (field_b & 0x1000) ? "add" : "sub",

		      sx_tab[(field_b >> 6) & 3],

		      sy_tab[(field_b >> 4) & 3],

		      du_tab[(field_b >> 0) & 3]);

	}

      else if ((field_b & 0xf0) == 0x10

	       && info->mach != bfd_mach_sh_dsp

	       && info->mach != bfd_mach_sh3_dsp)

	{

	  fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]);

	}

      else if ((field_b & 0xf3) != 0)

	{

	  fprintf_fn (stream, ".word 0x%x\t", field_b);

	}

      fprintf_fn (stream, "pmuls%c%s,%s,%s",

		  field_b & 0x2000 ? ' ' : '\t',

		  se_tab[(field_b >> 10) & 3],

		  sf_tab[(field_b >>  8) & 3],

		  sg_tab[(field_b >>  2) & 3]);

      return;

    }

  nib1 = PPIC;

  nib2 = field_b >> 12 & 0xf;

  nib3 = field_b >> 8 & 0xf;

  nib4 = field_b >> 4 & 0xf;

  switch (nib3 & 0x3)

    {

    case 0:

      dc = "";

      nib1 = PPI3;

      break;

    case 1:

      dc = "";

      break;

    case 2:

      dc = "dct ";

      nib3 -= 1;

      break;

    case 3:

      dc = "dcf ";

      nib3 -= 2;

      break;

    }

  if (nib1 == PPI3)

    altnib1 = PPI3NC;

  else

    altnib1 = nib1;

  for (op = sh_table; op->name; op++)

    {

      if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1)

	  && op->nibbles[2] == nib2

	  && op->nibbles[3] == nib3)

	{

	  int n;

	  switch (op->nibbles[4])

	    {

	    case HEX_0:

	      break;

	    case HEX_XX00:

	      if ((nib4 & 3) != 0)

		continue;

	      break;

	    case HEX_1:

	      if ((nib4 & 3) != 1)

		continue;

	      break;

	    case HEX_00YY:

	      if ((nib4 & 0xc) != 0)

		continue;

	      break;

	    case HEX_4:

	      if ((nib4 & 0xc) != 4)

		continue;

	      break;

	    default:

	      abort ();

	    }

	  fprintf_fn (stream, "%s%s\t", dc, op->name);

	  for (n = 0; n < 3 && op->arg[n] != A_END; n++)

	    {

	      if (n && op->arg[1] != A_END)

		fprintf_fn (stream, ",");

	      switch (op->arg[n])

		{

		case DSP_REG_N:

		  print_dsp_reg (field_b & 0xf, fprintf_fn, stream);

		  break;

		case DSP_REG_X:

		  fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]);

		  break;

		case DSP_REG_Y:

		  fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]);

		  break;

		case A_MACH:

		  fprintf_fn (stream, "mach");

		  break;

		case A_MACL:

		  fprintf_fn (stream, "macl");

		  break;

		default:

		  abort ();

		}

	    }

	  return;

	}

    }

  /* Not found.  */

  fprintf_fn (stream, ".word 0x%x", field_b);

}


static int monitor_parse(const char *devname)

{

    static int index = 0;

    char label[32];

    if (strcmp(devname, "none") == 0)

        return 0;

    if (index == MAX_MONITOR_DEVICES) {

        fprintf(stderr, "qemu: too many monitor devices\n");

        exit(1);

    }

    if (index == 0) {

        snprintf(label, sizeof(label), "monitor");

    } else {

        snprintf(label, sizeof(label), "monitor%d", index);

    }

    monitor_hds[index] = qemu_chr_open(label, devname, NULL);

    if (!monitor_hds[index]) {

        fprintf(stderr, "qemu: could not open monitor device '%s'\n",

                devname);

        return -1;

    }

    index++;

    return 0;

}


void ppc_store_sdr1(CPUPPCState *env, target_ulong value)

{

    qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);

    assert(!env->external_htab);

    env->spr[SPR_SDR1] = value;

#if defined(TARGET_PPC64)

    if (env->mmu_model & POWERPC_MMU_64) {

        PowerPCCPU *cpu = ppc_env_get_cpu(env);

        Error *local_err = NULL;

        ppc_hash64_set_sdr1(cpu, value, &local_err);

        if (local_err) {

            error_report_err(local_err);

            error_free(local_err);

        }

    } else

#endif /* defined(TARGET_PPC64) */

    {

        /* FIXME: Should check for valid HTABMASK values */

        env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;

        env->htab_base = value & SDR_32_HTABORG;

    }

}


static av_always_inline void idct_internal(uint8_t *dst, DCTELEM *block, int stride, int block_stride, int shift, int add){

    int i;

    uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;

    block[0] += 1<<(shift-1);

    for(i=0; i<4; i++){

        const int z0=  block[0 + block_stride*i]     +  block[2 + block_stride*i];

        const int z1=  block[0 + block_stride*i]     -  block[2 + block_stride*i];

        const int z2= (block[1 + block_stride*i]>>1) -  block[3 + block_stride*i];

        const int z3=  block[1 + block_stride*i]     + (block[3 + block_stride*i]>>1);

        block[0 + block_stride*i]= z0 + z3;

        block[1 + block_stride*i]= z1 + z2;

        block[2 + block_stride*i]= z1 - z2;

        block[3 + block_stride*i]= z0 - z3;

    }

    for(i=0; i<4; i++){

        const int z0=  block[i + block_stride*0]     +  block[i + block_stride*2];

        const int z1=  block[i + block_stride*0]     -  block[i + block_stride*2];

        const int z2= (block[i + block_stride*1]>>1) -  block[i + block_stride*3];

        const int z3=  block[i + block_stride*1]     + (block[i + block_stride*3]>>1);

        dst[i + 0*stride]= cm[ add*dst[i + 0*stride] + ((z0 + z3) >> shift) ];

        dst[i + 1*stride]= cm[ add*dst[i + 1*stride] + ((z1 + z2) >> shift) ];

        dst[i + 2*stride]= cm[ add*dst[i + 2*stride] + ((z1 - z2) >> shift) ];

        dst[i + 3*stride]= cm[ add*dst[i + 3*stride] + ((z0 - z3) >> shift) ];

    }

}


static int mp_dacl_removexattr(FsContext *ctx,

                               const char *path, const char *name)

{

    int ret;

    char buffer[PATH_MAX];

    ret  = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);

    if (ret == -1 && errno == ENODATA) {

        /*

         * We don't get ENODATA error when trying to remove a

         * posix acl that is not present. So don't throw the error

         * even in case of mapped security model

         */

        errno = 0;

        ret = 0;

    }

    return ret;

}


void *qemu_thread_join(QemuThread *thread)

{

    QemuThreadData *data;

    void *ret;

    HANDLE handle;

    data = thread->data;

    if (!data) {

        return NULL;

    }

    /*

     * Because multiple copies of the QemuThread can exist via

     * qemu_thread_get_self, we need to store a value that cannot

     * leak there.  The simplest, non racy way is to store the TID,

     * discard the handle that _beginthreadex gives back, and

     * get another copy of the handle here.

     */

    EnterCriticalSection(&data->cs);

    if (!data->exited) {

        handle = OpenThread(SYNCHRONIZE, FALSE, thread->tid);

        LeaveCriticalSection(&data->cs);

        WaitForSingleObject(handle, INFINITE);

        CloseHandle(handle);

    } else {

        LeaveCriticalSection(&data->cs);

    }

    ret = data->ret;

    DeleteCriticalSection(&data->cs);

    g_free(data);

    return ret;

}


void OPPROTO op_sti(void)

{

    raise_exception(EXCP0D_GPF);

}


static void test_pci_spec(void)

{

    AHCIQState *ahci;

    ahci = ahci_boot();

    ahci_test_pci_spec(ahci);

    ahci_shutdown(ahci);

}


static uint32_t nvdimm_rw_label_data_check(NVDIMMDevice *nvdimm,

                                           uint32_t offset, uint32_t length)

{

    uint32_t ret = 3 /* Invalid Input Parameters */;

    if (offset + length < offset) {

        nvdimm_debug("offset %#x + length %#x is overflow.\n", offset,

                     length);

        return ret;

    }

    if (nvdimm->label_size < offset + length) {

        nvdimm_debug("position %#x is beyond label data (len = %" PRIx64 ").\n",

                     offset + length, nvdimm->label_size);

        return ret;

    }

    if (length > nvdimm_get_max_xfer_label_size()) {

        nvdimm_debug("length (%#x) is larger than max_xfer (%#x).\n",

                     length, nvdimm_get_max_xfer_label_size());

        return ret;

    }

    return 0 /* Success */;

}


static inline void gen_evmwumia(DisasContext *ctx)

{

    TCGv_i64 tmp;

    if (unlikely(!ctx->spe_enabled)) {

        gen_exception(ctx, POWERPC_EXCP_APU);

        return;

    }

    gen_evmwumi(ctx);            /* rD := rA * rB */

    tmp = tcg_temp_new_i64();

    /* acc := rD */

    gen_load_gpr64(tmp, rD(ctx->opcode));

    tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUState, spe_acc));

    tcg_temp_free_i64(tmp);

}


QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)

{

    QmpInputVisitor *v;

    v = g_malloc0(sizeof(*v));

    v->visitor.type = VISITOR_INPUT;

    v->visitor.start_struct = qmp_input_start_struct;

    v->visitor.end_struct = qmp_input_end_struct;

    v->visitor.start_list = qmp_input_start_list;

    v->visitor.next_list = qmp_input_next_list;

    v->visitor.end_list = qmp_input_end_list;

    v->visitor.start_alternate = qmp_input_start_alternate;

    v->visitor.type_int64 = qmp_input_type_int64;

    v->visitor.type_uint64 = qmp_input_type_uint64;

    v->visitor.type_bool = qmp_input_type_bool;

    v->visitor.type_str = qmp_input_type_str;

    v->visitor.type_number = qmp_input_type_number;

    v->visitor.type_any = qmp_input_type_any;

    v->visitor.optional = qmp_input_optional;

    v->strict = strict;

    qmp_input_push(v, obj, NULL);

    qobject_incref(obj);

    return v;

}


static int mxf_parse_index(MXFContext *mxf, int track_id, AVStream *st)

{

    int64_t accumulated_offset = 0;

    int j, k, ret, nb_sorted_segments;

    MXFIndexTableSegment **sorted_segments;

    int n_delta = track_id - 1;  /* TrackID = 1-based stream index */

    if (track_id < 1) {

        av_log(mxf->fc, AV_LOG_ERROR, "TrackID not positive: %i\n", track_id);

        return AVERROR_INVALIDDATA;

    }

    if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)))

        return ret;

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

        int duration, sample_duration = 1, last_sample_size = 0;

        int64_t segment_size;

        MXFIndexTableSegment *tableseg = sorted_segments[j];

        /* reset accumulated_offset on BodySID change */

        if (j > 0 && tableseg->body_sid != sorted_segments[j-1]->body_sid)

            accumulated_offset = 0;

        if (n_delta >= tableseg->nb_delta_entries && st->index != 0)

            continue;

        duration = tableseg->index_duration > 0 ? tableseg->index_duration :

            st->duration - st->nb_index_entries;

        segment_size = tableseg->edit_unit_byte_count * duration;

        /* check small EditUnitByteCount for audio */

        if (tableseg->edit_unit_byte_count && tableseg->edit_unit_byte_count < 32

            && !tableseg->index_duration) {

            /* duration might be prime relative to the new sample_duration,

             * which means we need to handle the last frame differently */

            sample_duration = 8192;

            last_sample_size = (duration % sample_duration) * tableseg->edit_unit_byte_count;

            tableseg->edit_unit_byte_count *= sample_duration;

            duration /= sample_duration;

            if (last_sample_size) duration++;

        }

        for (k = 0; k < duration; k++) {

            int64_t pos;

            int size, flags = 0;

            if (k < tableseg->nb_index_entries) {

                pos = tableseg->stream_offset_entries[k];

                if (n_delta < tableseg->nb_delta_entries) {

                    if (n_delta < tableseg->nb_delta_entries - 1) {

                        size =

                            tableseg->slice_offset_entries[k][tableseg->slice[n_delta+1]-1] +

                            tableseg->element_delta[n_delta+1] -

                            tableseg->element_delta[n_delta];

                        if (tableseg->slice[n_delta] > 0)

                            size -= tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1];

                    } else if (k < duration - 1) {

                        size = tableseg->stream_offset_entries[k+1] -

                            tableseg->stream_offset_entries[k] -

                            tableseg->slice_offset_entries[k][tableseg->slice[tableseg->nb_delta_entries-1]-1] -

                            tableseg->element_delta[tableseg->nb_delta_entries-1];

                    } else

                        size = 0;

                    if (tableseg->slice[n_delta] > 0)

                        pos += tableseg->slice_offset_entries[k][tableseg->slice[n_delta]-1];

                    pos += tableseg->element_delta[n_delta];

                } else

                    size = 0;

                flags = !(tableseg->flag_entries[k] & 0x30) ? AVINDEX_KEYFRAME : 0;

            } else {

                pos = (int64_t)k * tableseg->edit_unit_byte_count + accumulated_offset;

                if (n_delta < tableseg->nb_delta_entries - 1)

                    size = tableseg->element_delta[n_delta+1] - tableseg->element_delta[n_delta];

                else {

                    /* use smaller size for last sample if we should */

                    if (last_sample_size && k == duration - 1)

                        size = last_sample_size;

                    else

                        size = tableseg->edit_unit_byte_count;

                    if (tableseg->nb_delta_entries)

                        size -= tableseg->element_delta[tableseg->nb_delta_entries-1];

                }

                if (n_delta < tableseg->nb_delta_entries)

                    pos += tableseg->element_delta[n_delta];

                flags = AVINDEX_KEYFRAME;

            }

            if (mxf_absolute_bodysid_offset(mxf, tableseg->body_sid, pos, &pos) < 0) {

                /* probably partial file - no point going further for this stream */

                break;

            }

            av_dlog(mxf->fc, "Stream %d IndexEntry %d TrackID %d Offset %"PRIx64" Timestamp %"PRId64"\n",

                    st->index, st->nb_index_entries, track_id, pos, sample_duration * st->nb_index_entries);

            if ((ret = av_add_index_entry(st, pos, sample_duration * st->nb_index_entries, size, 0, flags)) < 0)

                return ret;

        }

        accumulated_offset += segment_size;

    }

    av_free(sorted_segments);

    return 0;

}


static void fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, const HEVCContext *h,

                                    DXVA_PicParams_HEVC *pp)

{

    const HEVCFrame *current_picture = h->ref;

    int i, j, k;

    memset(pp, 0, sizeof(*pp));

    pp->PicWidthInMinCbsY  = h->sps->min_cb_width;

    pp->PicHeightInMinCbsY = h->sps->min_cb_height;

    pp->wFormatAndSequenceInfoFlags = (h->sps->chroma_format_idc          <<  0) |

                                      (h->sps->separate_colour_plane_flag <<  2) |

                                      ((h->sps->bit_depth - 8)            <<  3) |

                                      ((h->sps->bit_depth - 8)            <<  6) |

                                      ((h->sps->log2_max_poc_lsb - 4)     <<  9) |

                                      (0                                  << 13) |

                                      (0                                  << 14) |

                                      (0                                  << 15);

    fill_picture_entry(&pp->CurrPic, ff_dxva2_get_surface_index(avctx, ctx, current_picture->frame), 0);

    pp->sps_max_dec_pic_buffering_minus1         = h->sps->temporal_layer[h->sps->max_sub_layers - 1].max_dec_pic_buffering - 1;

    pp->log2_min_luma_coding_block_size_minus3   = h->sps->log2_min_cb_size - 3;

    pp->log2_diff_max_min_luma_coding_block_size = h->sps->log2_diff_max_min_coding_block_size;

    pp->log2_min_transform_block_size_minus2     = h->sps->log2_min_tb_size - 2;

    pp->log2_diff_max_min_transform_block_size   = h->sps->log2_max_trafo_size  - h->sps->log2_min_tb_size;

    pp->max_transform_hierarchy_depth_inter      = h->sps->max_transform_hierarchy_depth_inter;

    pp->max_transform_hierarchy_depth_intra      = h->sps->max_transform_hierarchy_depth_intra;

    pp->num_short_term_ref_pic_sets              = h->sps->nb_st_rps;

    pp->num_long_term_ref_pics_sps               = h->sps->num_long_term_ref_pics_sps;

    pp->num_ref_idx_l0_default_active_minus1     = h->pps->num_ref_idx_l0_default_active - 1;

    pp->num_ref_idx_l1_default_active_minus1     = h->pps->num_ref_idx_l1_default_active - 1;

    pp->init_qp_minus26                          = h->pps->pic_init_qp_minus26;

    if (h->sh.short_term_ref_pic_set_sps_flag == 0 && h->sh.short_term_rps) {

        pp->ucNumDeltaPocsOfRefRpsIdx            = h->sh.short_term_rps->num_delta_pocs;

        pp->wNumBitsForShortTermRPSInSlice       = h->sh.short_term_ref_pic_set_size;

    }

    pp->dwCodingParamToolFlags = (h->sps->scaling_list_enable_flag               <<  0) |

                                 (h->sps->amp_enabled_flag                       <<  1) |

                                 (h->sps->sao_enabled                            <<  2) |

                                 (h->sps->pcm_enabled_flag                       <<  3) |

                                 ((h->sps->pcm_enabled_flag ? (h->sps->pcm.bit_depth - 1) : 0)            <<  4) |

                                 ((h->sps->pcm_enabled_flag ? (h->sps->pcm.bit_depth_chroma - 1) : 0)     <<  8) |

                                 ((h->sps->pcm_enabled_flag ? (h->sps->pcm.log2_min_pcm_cb_size - 3) : 0) << 12) |

                                 ((h->sps->pcm_enabled_flag ? (h->sps->pcm.log2_max_pcm_cb_size - h->sps->pcm.log2_min_pcm_cb_size) : 0) << 14) |

                                 (h->sps->pcm.loop_filter_disable_flag           << 16) |

                                 (h->sps->long_term_ref_pics_present_flag        << 17) |

                                 (h->sps->sps_temporal_mvp_enabled_flag          << 18) |

                                 (h->sps->sps_strong_intra_smoothing_enable_flag << 19) |

                                 (h->pps->dependent_slice_segments_enabled_flag  << 20) |

                                 (h->pps->output_flag_present_flag               << 21) |

                                 (h->pps->num_extra_slice_header_bits            << 22) |

                                 (h->pps->sign_data_hiding_flag                  << 25) |

                                 (h->pps->cabac_init_present_flag                << 26) |

                                 (0                                              << 27);

    pp->dwCodingSettingPicturePropertyFlags = (h->pps->constrained_intra_pred_flag                <<  0) |

                                              (h->pps->transform_skip_enabled_flag                <<  1) |

                                              (h->pps->cu_qp_delta_enabled_flag                   <<  2) |

                                              (h->pps->pic_slice_level_chroma_qp_offsets_present_flag <<  3) |

                                              (h->pps->weighted_pred_flag                         <<  4) |

                                              (h->pps->weighted_bipred_flag                       <<  5) |

                                              (h->pps->transquant_bypass_enable_flag              <<  6) |

                                              (h->pps->tiles_enabled_flag                         <<  7) |

                                              (h->pps->entropy_coding_sync_enabled_flag           <<  8) |

                                              (h->pps->uniform_spacing_flag                       <<  9) |

                                              ((h->pps->tiles_enabled_flag ? h->pps->loop_filter_across_tiles_enabled_flag : 0) << 10) |

                                              (h->pps->seq_loop_filter_across_slices_enabled_flag << 11) |

                                              (h->pps->deblocking_filter_override_enabled_flag    << 12) |

                                              (h->pps->disable_dbf                                << 13) |

                                              (h->pps->lists_modification_present_flag            << 14) |

                                              (h->pps->slice_header_extension_present_flag        << 15) |

                                              (IS_IRAP(h)                                         << 16) |

                                              (IS_IDR(h)                                          << 17) |

                                              /* IntraPicFlag */

                                              (IS_IRAP(h)                                         << 18) |

                                              (0                                                  << 19);

    pp->pps_cb_qp_offset            = h->pps->cb_qp_offset;

    pp->pps_cr_qp_offset            = h->pps->cr_qp_offset;

    if (h->pps->tiles_enabled_flag) {

        pp->num_tile_columns_minus1 = h->pps->num_tile_columns - 1;

        pp->num_tile_rows_minus1    = h->pps->num_tile_rows - 1;

        if (!h->pps->uniform_spacing_flag) {

            for (i = 0; i < h->pps->num_tile_columns; i++)

                pp->column_width_minus1[i] = h->pps->column_width[i] - 1;

            for (i = 0; i < h->pps->num_tile_rows; i++)

                pp->row_height_minus1[i] = h->pps->row_height[i] - 1;

        }

    }

    pp->diff_cu_qp_delta_depth           = h->pps->diff_cu_qp_delta_depth;

    pp->pps_beta_offset_div2             = h->pps->beta_offset / 2;

    pp->pps_tc_offset_div2               = h->pps->tc_offset / 2;

    pp->log2_parallel_merge_level_minus2 = h->pps->log2_parallel_merge_level - 2;

    pp->CurrPicOrderCntVal               = h->poc;

    // empty the lists

    memset(&pp->RefPicList, 0xff, sizeof(pp->RefPicList));

    memset(&pp->RefPicSetStCurrBefore, 0xff, sizeof(pp->RefPicSetStCurrBefore));

    memset(&pp->RefPicSetStCurrAfter, 0xff, sizeof(pp->RefPicSetStCurrAfter));

    memset(&pp->RefPicSetLtCurr, 0xff, sizeof(pp->RefPicSetLtCurr));

    // fill RefPicList from the DPB

    for (i = 0, j = 0; i < FF_ARRAY_ELEMS(h->DPB); i++) {

        const HEVCFrame *frame = &h->DPB[i];

        if (frame != current_picture && (frame->flags & (HEVC_FRAME_FLAG_LONG_REF | HEVC_FRAME_FLAG_SHORT_REF))) {

            fill_picture_entry(&pp->RefPicList[j], ff_dxva2_get_surface_index(avctx, ctx, frame->frame), !!(frame->flags & HEVC_FRAME_FLAG_LONG_REF));

            pp->PicOrderCntValList[j] = frame->poc;

            j++;

        }

    }

    #define DO_REF_LIST(ref_idx, ref_list) { \

        const RefPicList *rpl = &h->rps[ref_idx]; \

        av_assert0(rpl->nb_refs <= FF_ARRAY_ELEMS(pp->ref_list)); \

        for (j = 0, k = 0; j < rpl->nb_refs; j++) { \

            if (rpl->ref[j]) { \

                pp->ref_list[k] = get_refpic_index(pp, ff_dxva2_get_surface_index(avctx, ctx, rpl->ref[j]->frame)); \

                k++; \

            } \

        } \

    }

    // Fill short term and long term lists

    DO_REF_LIST(ST_CURR_BEF, RefPicSetStCurrBefore);

    DO_REF_LIST(ST_CURR_AFT, RefPicSetStCurrAfter);

    DO_REF_LIST(LT_CURR, RefPicSetLtCurr);

    pp->StatusReportFeedbackNumber = 1 + DXVA_CONTEXT_REPORT_ID(avctx, ctx)++;

}


static void isa_ipmi_bmc_check(Object *obj, const char *name,

                               Object *val, Error **errp)

{

    IPMIBmc *bmc = IPMI_BMC(val);

    if (bmc->intf)

        error_setg(errp, "BMC object is already in use");

}


av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],

                                     int fullRange, int brightness,

                                     int contrast, int saturation)

{

    const int isRgb = c->dstFormat == AV_PIX_FMT_RGB32     ||

                      c->dstFormat == AV_PIX_FMT_RGB32_1   ||

                      c->dstFormat == AV_PIX_FMT_BGR24     ||

                      c->dstFormat == AV_PIX_FMT_RGB565BE  ||

                      c->dstFormat == AV_PIX_FMT_RGB565LE  ||

                      c->dstFormat == AV_PIX_FMT_RGB555BE  ||

                      c->dstFormat == AV_PIX_FMT_RGB555LE  ||

                      c->dstFormat == AV_PIX_FMT_RGB444BE  ||

                      c->dstFormat == AV_PIX_FMT_RGB444LE  ||

                      c->dstFormat == AV_PIX_FMT_RGB8      ||

                      c->dstFormat == AV_PIX_FMT_RGB4      ||

                      c->dstFormat == AV_PIX_FMT_RGB4_BYTE ||

                      c->dstFormat == AV_PIX_FMT_MONOBLACK;

    const int isNotNe = c->dstFormat == AV_PIX_FMT_NE(RGB565LE, RGB565BE) ||

                        c->dstFormat == AV_PIX_FMT_NE(RGB555LE, RGB555BE) ||

                        c->dstFormat == AV_PIX_FMT_NE(RGB444LE, RGB444BE) ||

                        c->dstFormat == AV_PIX_FMT_NE(BGR565LE, BGR565BE) ||

                        c->dstFormat == AV_PIX_FMT_NE(BGR555LE, BGR555BE) ||

                        c->dstFormat == AV_PIX_FMT_NE(BGR444LE, BGR444BE);

    const int bpp = c->dstFormatBpp;

    uint8_t *y_table;

    uint16_t *y_table16;

    uint32_t *y_table32;

    int i, base, rbase, gbase, bbase, av_uninit(abase), needAlpha;

    const int yoffs = fullRange ? 384 : 326;

    int64_t crv =  inv_table[0];

    int64_t cbu =  inv_table[1];

    int64_t cgu = -inv_table[2];

    int64_t cgv = -inv_table[3];

    int64_t cy  = 1 << 16;

    int64_t oy  = 0;

    int64_t yb  = 0;

    if (!fullRange) {

        cy = (cy * 255) / 219;

        oy = 16 << 16;

    } else {

        crv = (crv * 224) / 255;

        cbu = (cbu * 224) / 255;

        cgu = (cgu * 224) / 255;

        cgv = (cgv * 224) / 255;

    }

    cy   = (cy  * contrast)              >> 16;

    crv  = (crv * contrast * saturation) >> 32;

    cbu  = (cbu * contrast * saturation) >> 32;

    cgu  = (cgu * contrast * saturation) >> 32;

    cgv  = (cgv * contrast * saturation) >> 32;

    oy  -= 256 * brightness;

    c->uOffset = 0x0400040004000400LL;

    c->vOffset = 0x0400040004000400LL;

    c->yCoeff  = roundToInt16(cy  * 8192) * 0x0001000100010001ULL;

    c->vrCoeff = roundToInt16(crv * 8192) * 0x0001000100010001ULL;

    c->ubCoeff = roundToInt16(cbu * 8192) * 0x0001000100010001ULL;

    c->vgCoeff = roundToInt16(cgv * 8192) * 0x0001000100010001ULL;

    c->ugCoeff = roundToInt16(cgu * 8192) * 0x0001000100010001ULL;

    c->yOffset = roundToInt16(oy  *    8) * 0x0001000100010001ULL;

    c->yuv2rgb_y_coeff   = (int16_t)roundToInt16(cy  << 13);

    c->yuv2rgb_y_offset  = (int16_t)roundToInt16(oy  <<  9);

    c->yuv2rgb_v2r_coeff = (int16_t)roundToInt16(crv << 13);

    c->yuv2rgb_v2g_coeff = (int16_t)roundToInt16(cgv << 13);

    c->yuv2rgb_u2g_coeff = (int16_t)roundToInt16(cgu << 13);

    c->yuv2rgb_u2b_coeff = (int16_t)roundToInt16(cbu << 13);

    //scale coefficients by cy

    crv = ((crv << 16) + 0x8000) / cy;

    cbu = ((cbu << 16) + 0x8000) / cy;

    cgu = ((cgu << 16) + 0x8000) / cy;

    cgv = ((cgv << 16) + 0x8000) / cy;

    av_freep(&c->yuvTable);

    switch (bpp) {

    case 1:

        c->yuvTable = av_malloc(1024);

        y_table     = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024 - 110; i++) {

            y_table[i + 110]  = av_clip_uint8((yb + 0x8000) >> 16) >> 7;

            yb               += cy;

        }

        fill_table(c->table_gU, 1, cgu, y_table + yoffs);

        fill_gv_table(c->table_gV, 1, cgv);

        break;

    case 4:

    case 4 | 128:

        rbase       = isRgb ? 3 : 0;

        gbase       = 1;

        bbase       = isRgb ? 0 : 3;

        c->yuvTable = av_malloc(1024 * 3);

        y_table     = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024 - 110; i++) {

            int yval                = av_clip_uint8((yb + 0x8000) >> 16);

            y_table[i + 110]        = (yval >> 7)        << rbase;

            y_table[i +  37 + 1024] = ((yval + 43) / 85) << gbase;

            y_table[i + 110 + 2048] = (yval >> 7)        << bbase;

            yb += cy;

        }

        fill_table(c->table_rV, 1, crv, y_table + yoffs);

        fill_table(c->table_gU, 1, cgu, y_table + yoffs + 1024);

        fill_table(c->table_bU, 1, cbu, y_table + yoffs + 2048);

        fill_gv_table(c->table_gV, 1, cgv);

        break;

    case 8:

        rbase       = isRgb ? 5 : 0;

        gbase       = isRgb ? 2 : 3;

        bbase       = isRgb ? 0 : 6;

        c->yuvTable = av_malloc(1024 * 3);

        y_table     = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024 - 38; i++) {

            int yval               = av_clip_uint8((yb + 0x8000) >> 16);

            y_table[i + 16]        = ((yval + 18) / 36) << rbase;

            y_table[i + 16 + 1024] = ((yval + 18) / 36) << gbase;

            y_table[i + 37 + 2048] = ((yval + 43) / 85) << bbase;

            yb += cy;

        }

        fill_table(c->table_rV, 1, crv, y_table + yoffs);

        fill_table(c->table_gU, 1, cgu, y_table + yoffs + 1024);

        fill_table(c->table_bU, 1, cbu, y_table + yoffs + 2048);

        fill_gv_table(c->table_gV, 1, cgv);

        break;

    case 12:

        rbase       = isRgb ? 8 : 0;

        gbase       = 4;

        bbase       = isRgb ? 0 : 8;

        c->yuvTable = av_malloc(1024 * 3 * 2);

        y_table16   = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024; i++) {

            uint8_t yval        = av_clip_uint8((yb + 0x8000) >> 16);

            y_table16[i]        = (yval >> 4) << rbase;

            y_table16[i + 1024] = (yval >> 4) << gbase;

            y_table16[i + 2048] = (yval >> 4) << bbase;

            yb += cy;

        }

        if (isNotNe)

            for (i = 0; i < 1024 * 3; i++)

                y_table16[i] = av_bswap16(y_table16[i]);

        fill_table(c->table_rV, 2, crv, y_table16 + yoffs);

        fill_table(c->table_gU, 2, cgu, y_table16 + yoffs + 1024);

        fill_table(c->table_bU, 2, cbu, y_table16 + yoffs + 2048);

        fill_gv_table(c->table_gV, 2, cgv);

        break;

    case 15:

    case 16:

        rbase       = isRgb ? bpp - 5 : 0;

        gbase       = 5;

        bbase       = isRgb ? 0 : (bpp - 5);

        c->yuvTable = av_malloc(1024 * 3 * 2);

        y_table16   = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024; i++) {

            uint8_t yval        = av_clip_uint8((yb + 0x8000) >> 16);

            y_table16[i]        = (yval >> 3)          << rbase;

            y_table16[i + 1024] = (yval >> (18 - bpp)) << gbase;

            y_table16[i + 2048] = (yval >> 3)          << bbase;

            yb += cy;

        }

        if (isNotNe)

            for (i = 0; i < 1024 * 3; i++)

                y_table16[i] = av_bswap16(y_table16[i]);

        fill_table(c->table_rV, 2, crv, y_table16 + yoffs);

        fill_table(c->table_gU, 2, cgu, y_table16 + yoffs + 1024);

        fill_table(c->table_bU, 2, cbu, y_table16 + yoffs + 2048);

        fill_gv_table(c->table_gV, 2, cgv);

        break;

    case 24:

    case 48:

        c->yuvTable = av_malloc(1024);

        y_table     = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024; i++) {

            y_table[i]  = av_clip_uint8((yb + 0x8000) >> 16);

            yb         += cy;

        }

        fill_table(c->table_rV, 1, crv, y_table + yoffs);

        fill_table(c->table_gU, 1, cgu, y_table + yoffs);

        fill_table(c->table_bU, 1, cbu, y_table + yoffs);

        fill_gv_table(c->table_gV, 1, cgv);

        break;

    case 32:

    case 64:

        base      = (c->dstFormat == AV_PIX_FMT_RGB32_1 ||

                     c->dstFormat == AV_PIX_FMT_BGR32_1) ? 8 : 0;

        rbase     = base + (isRgb ? 16 : 0);

        gbase     = base + 8;

        bbase     = base + (isRgb ? 0 : 16);

        needAlpha = CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat);

        if (!needAlpha)

            abase = (base + 24) & 31;

        c->yuvTable = av_malloc(1024 * 3 * 4);

        y_table32   = c->yuvTable;

        yb = -(384 << 16) - oy;

        for (i = 0; i < 1024; i++) {

            unsigned yval       = av_clip_uint8((yb + 0x8000) >> 16);

            y_table32[i]        = (yval << rbase) +

                                  (needAlpha ? 0 : (255u << abase));

            y_table32[i + 1024] =  yval << gbase;

            y_table32[i + 2048] =  yval << bbase;

            yb += cy;

        }

        fill_table(c->table_rV, 4, crv, y_table32 + yoffs);

        fill_table(c->table_gU, 4, cgu, y_table32 + yoffs + 1024);

        fill_table(c->table_bU, 4, cbu, y_table32 + yoffs + 2048);

        fill_gv_table(c->table_gV, 4, cgv);

        break;

    default:

        if(!isPlanar(c->dstFormat) || bpp <= 24)

            av_log(c, AV_LOG_ERROR, "%ibpp not supported by yuv2rgb\n", bpp);

        return -1;

    }

    return 0;

}