static void filter_mb( H264Context *h, int mb_x, int mb_y, uint8_t *img_y, uint8_t *img_cb, uint8_t *img_cr, unsigned int linesize, unsigned int uvlinesize) {

    MpegEncContext * const s = &h->s;

    const int mb_xy= mb_x + mb_y*s->mb_stride;

    const int mb_type = s->current_picture.mb_type[mb_xy];

    const int mvy_limit = IS_INTERLACED(mb_type) ? 2 : 4;

    int first_vertical_edge_done = 0;

    int dir;

    /* FIXME: A given frame may occupy more than one position in

     * the reference list. So ref2frm should be populated with

     * frame numbers, not indices. */

    static const int ref2frm[34] = {-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,

                                    16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};

    //for sufficiently low qp, filtering wouldn't do anything

    //this is a conservative estimate: could also check beta_offset and more accurate chroma_qp

    if(!FRAME_MBAFF){

        int qp_thresh = 15 - h->slice_alpha_c0_offset - FFMAX(0, h->pps.chroma_qp_index_offset);

        int qp = s->current_picture.qscale_table[mb_xy];

        if(qp <= qp_thresh

           && (mb_x == 0 || ((qp + s->current_picture.qscale_table[mb_xy-1] + 1)>>1) <= qp_thresh)

           && (mb_y == 0 || ((qp + s->current_picture.qscale_table[h->top_mb_xy] + 1)>>1) <= qp_thresh)){

            return;

        }

    }

    if (FRAME_MBAFF

            // left mb is in picture

            && h->slice_table[mb_xy-1] != 255

            // and current and left pair do not have the same interlaced type

            && (IS_INTERLACED(mb_type) != IS_INTERLACED(s->current_picture.mb_type[mb_xy-1]))

            // and left mb is in the same slice if deblocking_filter == 2

            && (h->deblocking_filter!=2 || h->slice_table[mb_xy-1] == h->slice_table[mb_xy])) {

        /* First vertical edge is different in MBAFF frames

         * There are 8 different bS to compute and 2 different Qp

         */

        const int pair_xy = mb_x + (mb_y&~1)*s->mb_stride;

        const int left_mb_xy[2] = { pair_xy-1, pair_xy-1+s->mb_stride };

        int16_t bS[8];

        int qp[2];

        int chroma_qp[2];

        int mb_qp, mbn0_qp, mbn1_qp;

        int i;

        first_vertical_edge_done = 1;

        if( IS_INTRA(mb_type) )

            bS[0] = bS[1] = bS[2] = bS[3] = bS[4] = bS[5] = bS[6] = bS[7] = 4;

        else {

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

                int mbn_xy = MB_FIELD ? left_mb_xy[i>>2] : left_mb_xy[i&1];

                if( IS_INTRA( s->current_picture.mb_type[mbn_xy] ) )

                    bS[i] = 4;

                else if( h->non_zero_count_cache[12+8*(i>>1)] != 0 ||

                         /* FIXME: with 8x8dct + cavlc, should check cbp instead of nnz */

                         h->non_zero_count[mbn_xy][MB_FIELD ? i&3 : (i>>2)+(mb_y&1)*2] )

                    bS[i] = 2;

                else

                    bS[i] = 1;

            }

        }

        mb_qp = s->current_picture.qscale_table[mb_xy];

        mbn0_qp = s->current_picture.qscale_table[left_mb_xy[0]];

        mbn1_qp = s->current_picture.qscale_table[left_mb_xy[1]];

        qp[0] = ( mb_qp + mbn0_qp + 1 ) >> 1;

        chroma_qp[0] = ( get_chroma_qp( h, mb_qp ) +

                         get_chroma_qp( h, mbn0_qp ) + 1 ) >> 1;

        qp[1] = ( mb_qp + mbn1_qp + 1 ) >> 1;

        chroma_qp[1] = ( get_chroma_qp( h, mb_qp ) +

                         get_chroma_qp( h, mbn1_qp ) + 1 ) >> 1;

        /* Filter edge */

        tprintf(s->avctx, "filter mb:%d/%d MBAFF, QPy:%d/%d, QPc:%d/%d ls:%d uvls:%d", mb_x, mb_y, qp[0], qp[1], chroma_qp[0], chroma_qp[1], linesize, uvlinesize);

        { int i; for (i = 0; i < 8; i++) tprintf(s->avctx, " bS[%d]:%d", i, bS[i]); tprintf(s->avctx, "\n"); }

        filter_mb_mbaff_edgev ( h, &img_y [0], linesize,   bS, qp );

        filter_mb_mbaff_edgecv( h, &img_cb[0], uvlinesize, bS, chroma_qp );

        filter_mb_mbaff_edgecv( h, &img_cr[0], uvlinesize, bS, chroma_qp );

    }

    /* dir : 0 -> vertical edge, 1 -> horizontal edge */

    for( dir = 0; dir < 2; dir++ )

    {

        int edge;

        const int mbm_xy = dir == 0 ? mb_xy -1 : h->top_mb_xy;

        const int mbm_type = s->current_picture.mb_type[mbm_xy];

        int start = h->slice_table[mbm_xy] == 255 ? 1 : 0;

        const int edges = (mb_type & (MB_TYPE_16x16|MB_TYPE_SKIP))

                                  == (MB_TYPE_16x16|MB_TYPE_SKIP) ? 1 : 4;

        // how often to recheck mv-based bS when iterating between edges

        const int mask_edge = (mb_type & (MB_TYPE_16x16 | (MB_TYPE_16x8 << dir))) ? 3 :

                              (mb_type & (MB_TYPE_8x16 >> dir)) ? 1 : 0;

        // how often to recheck mv-based bS when iterating along each edge

        const int mask_par0 = mb_type & (MB_TYPE_16x16 | (MB_TYPE_8x16 >> dir));

        if (first_vertical_edge_done) {

            start = 1;

            first_vertical_edge_done = 0;

        }

        if (h->deblocking_filter==2 && h->slice_table[mbm_xy] != h->slice_table[mb_xy])

            start = 1;

        if (FRAME_MBAFF && (dir == 1) && ((mb_y&1) == 0) && start == 0

            && !IS_INTERLACED(mb_type)

            && IS_INTERLACED(mbm_type)

            ) {

            // This is a special case in the norm where the filtering must

            // be done twice (one each of the field) even if we are in a

            // frame macroblock.

            //

            static const int nnz_idx[4] = {4,5,6,3};

            unsigned int tmp_linesize   = 2 *   linesize;

            unsigned int tmp_uvlinesize = 2 * uvlinesize;

            int mbn_xy = mb_xy - 2 * s->mb_stride;

            int qp, chroma_qp;

            int i, j;

            int16_t bS[4];

            for(j=0; j<2; j++, mbn_xy += s->mb_stride){

                if( IS_INTRA(mb_type) ||

                    IS_INTRA(s->current_picture.mb_type[mbn_xy]) ) {

                    bS[0] = bS[1] = bS[2] = bS[3] = 3;

                } else {

                    const uint8_t *mbn_nnz = h->non_zero_count[mbn_xy];

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

                        if( h->non_zero_count_cache[scan8[0]+i] != 0 ||

                            mbn_nnz[nnz_idx[i]] != 0 )

                            bS[i] = 2;

                        else

                            bS[i] = 1;

                    }

                }

                // Do not use s->qscale as luma quantizer because it has not the same

                // value in IPCM macroblocks.

                qp = ( s->current_picture.qscale_table[mb_xy] + s->current_picture.qscale_table[mbn_xy] + 1 ) >> 1;

                tprintf(s->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d ls:%d uvls:%d", mb_x, mb_y, dir, edge, qp, tmp_linesize, tmp_uvlinesize);

                { int i; for (i = 0; i < 4; i++) tprintf(s->avctx, " bS[%d]:%d", i, bS[i]); tprintf(s->avctx, "\n"); }

                filter_mb_edgeh( h, &img_y[j*linesize], tmp_linesize, bS, qp );

                chroma_qp = ( h->chroma_qp +

                              get_chroma_qp( h, s->current_picture.qscale_table[mbn_xy] ) + 1 ) >> 1;

                filter_mb_edgech( h, &img_cb[j*uvlinesize], tmp_uvlinesize, bS, chroma_qp );

                filter_mb_edgech( h, &img_cr[j*uvlinesize], tmp_uvlinesize, bS, chroma_qp );

            }

            start = 1;

        }

        /* Calculate bS */

        for( edge = start; edge < edges; edge++ ) {

            /* mbn_xy: neighbor macroblock */

            const int mbn_xy = edge > 0 ? mb_xy : mbm_xy;

            const int mbn_type = s->current_picture.mb_type[mbn_xy];

            int16_t bS[4];

            int qp;

            if( (edge&1) && IS_8x8DCT(mb_type) )

                continue;

            if( IS_INTRA(mb_type) ||

                IS_INTRA(mbn_type) ) {

                int value;

                if (edge == 0) {

                    if (   (!IS_INTERLACED(mb_type) && !IS_INTERLACED(mbm_type))

                        || ((FRAME_MBAFF || (s->picture_structure != PICT_FRAME)) && (dir == 0))

                    ) {

                        value = 4;

                    } else {

                        value = 3;

                    }

                } else {

                    value = 3;

                }

                bS[0] = bS[1] = bS[2] = bS[3] = value;

            } else {

                int i, l;

                int mv_done;

                if( edge & mask_edge ) {

                    bS[0] = bS[1] = bS[2] = bS[3] = 0;

                    mv_done = 1;

                }

                else if( FRAME_MBAFF && IS_INTERLACED(mb_type ^ mbn_type)) {

                    bS[0] = bS[1] = bS[2] = bS[3] = 1;

                    mv_done = 1;

                }

                else if( mask_par0 && (edge || (mbn_type & (MB_TYPE_16x16 | (MB_TYPE_8x16 >> dir)))) ) {

                    int b_idx= 8 + 4 + edge * (dir ? 8:1);

                    int bn_idx= b_idx - (dir ? 8:1);

                    int v = 0;

                    for( l = 0; !v && l < 1 + (h->slice_type == B_TYPE); l++ ) {

                        v |= ref2frm[h->ref_cache[l][b_idx]+2] != ref2frm[h->ref_cache[l][bn_idx]+2] ||

                             FFABS( h->mv_cache[l][b_idx][0] - h->mv_cache[l][bn_idx][0] ) >= 4 ||

                             FFABS( h->mv_cache[l][b_idx][1] - h->mv_cache[l][bn_idx][1] ) >= mvy_limit;

                    }

                    bS[0] = bS[1] = bS[2] = bS[3] = v;

                    mv_done = 1;

                }

                else

                    mv_done = 0;

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

                    int x = dir == 0 ? edge : i;

                    int y = dir == 0 ? i    : edge;

                    int b_idx= 8 + 4 + x + 8*y;

                    int bn_idx= b_idx - (dir ? 8:1);

                    if( h->non_zero_count_cache[b_idx] != 0 ||

                        h->non_zero_count_cache[bn_idx] != 0 ) {

                        bS[i] = 2;

                    }

                    else if(!mv_done)

                    {

                        bS[i] = 0;

                        for( l = 0; l < 1 + (h->slice_type == B_TYPE); l++ ) {

                            if( ref2frm[h->ref_cache[l][b_idx]+2] != ref2frm[h->ref_cache[l][bn_idx]+2] ||

                                FFABS( h->mv_cache[l][b_idx][0] - h->mv_cache[l][bn_idx][0] ) >= 4 ||

                                FFABS( h->mv_cache[l][b_idx][1] - h->mv_cache[l][bn_idx][1] ) >= mvy_limit ) {

                                bS[i] = 1;

                                break;

                            }

                        }

                    }

                }

                if(bS[0]+bS[1]+bS[2]+bS[3] == 0)

                    continue;

            }

            /* Filter edge */

            // Do not use s->qscale as luma quantizer because it has not the same

            // value in IPCM macroblocks.

            qp = ( s->current_picture.qscale_table[mb_xy] + s->current_picture.qscale_table[mbn_xy] + 1 ) >> 1;

            //tprintf(s->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d, QPc:%d, QPcn:%d\n", mb_x, mb_y, dir, edge, qp, h->chroma_qp, s->current_picture.qscale_table[mbn_xy]);

            tprintf(s->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d ls:%d uvls:%d", mb_x, mb_y, dir, edge, qp, linesize, uvlinesize);

            { int i; for (i = 0; i < 4; i++) tprintf(s->avctx, " bS[%d]:%d", i, bS[i]); tprintf(s->avctx, "\n"); }

            if( dir == 0 ) {

                filter_mb_edgev( h, &img_y[4*edge], linesize, bS, qp );

                if( (edge&1) == 0 ) {

                    int chroma_qp = ( h->chroma_qp +

                                      get_chroma_qp( h, s->current_picture.qscale_table[mbn_xy] ) + 1 ) >> 1;

                    filter_mb_edgecv( h, &img_cb[2*edge], uvlinesize, bS, chroma_qp );

                    filter_mb_edgecv( h, &img_cr[2*edge], uvlinesize, bS, chroma_qp );

                }

            } else {

                filter_mb_edgeh( h, &img_y[4*edge*linesize], linesize, bS, qp );

                if( (edge&1) == 0 ) {

                    int chroma_qp = ( h->chroma_qp +

                                      get_chroma_qp( h, s->current_picture.qscale_table[mbn_xy] ) + 1 ) >> 1;

                    filter_mb_edgech( h, &img_cb[2*edge*uvlinesize], uvlinesize, bS, chroma_qp );

                    filter_mb_edgech( h, &img_cr[2*edge*uvlinesize], uvlinesize, bS, chroma_qp );

                }

            }

        }

    }

}


static void select_frame(AVFilterContext *ctx, AVFrame *frame)

{

    SelectContext *select = ctx->priv;

    AVFilterLink *inlink = ctx->inputs[0];

    double res;

    if (isnan(select->var_values[VAR_START_PTS]))

        select->var_values[VAR_START_PTS] = TS2D(frame->pts);

    if (isnan(select->var_values[VAR_START_T]))

        select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base);

    select->var_values[VAR_N  ] = inlink->frame_count;

    select->var_values[VAR_PTS] = TS2D(frame->pts);

    select->var_values[VAR_T  ] = TS2D(frame->pts) * av_q2d(inlink->time_base);

    select->var_values[VAR_POS] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);

    switch (inlink->type) {

    case AVMEDIA_TYPE_AUDIO:

        select->var_values[VAR_SAMPLES_N] = frame->nb_samples;

        break;

    case AVMEDIA_TYPE_VIDEO:

        select->var_values[VAR_INTERLACE_TYPE] =

            !frame->interlaced_frame ? INTERLACE_TYPE_P :

        frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;

        select->var_values[VAR_PICT_TYPE] = frame->pict_type;

#if CONFIG_AVCODEC

        if (select->do_scene_detect) {

            char buf[32];

            select->var_values[VAR_SCENE] = get_scene_score(ctx, frame);

            // TODO: document metadata

            snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]);

            av_dict_set(avpriv_frame_get_metadatap(frame), "lavfi.scene_score", buf, 0);

        }

#endif

        break;

    }

    select->select = res = av_expr_eval(select->expr, select->var_values, NULL);

    av_log(inlink->dst, AV_LOG_DEBUG,

           "n:%f pts:%f t:%f key:%d",

           select->var_values[VAR_N],

           select->var_values[VAR_PTS],

           select->var_values[VAR_T],

           (int)select->var_values[VAR_KEY]);

    switch (inlink->type) {

    case AVMEDIA_TYPE_VIDEO:

        av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c scene:%f",

               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_P ? 'P' :

               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_T ? 'T' :

               select->var_values[VAR_INTERLACE_TYPE] == INTERLACE_TYPE_B ? 'B' : '?',

               av_get_picture_type_char(select->var_values[VAR_PICT_TYPE]),

               select->var_values[VAR_SCENE]);

        break;

    case AVMEDIA_TYPE_AUDIO:

        av_log(inlink->dst, AV_LOG_DEBUG, " samples_n:%d consumed_samples_n:%d",

               (int)select->var_values[VAR_SAMPLES_N],

               (int)select->var_values[VAR_CONSUMED_SAMPLES_N]);

        break;

    }

    if (res == 0) {

        select->select_out = -1; /* drop */

    } else if (isnan(res) || res < 0) {

        select->select_out = 0; /* first output */

    } else {

        select->select_out = FFMIN(ceilf(res)-1, select->nb_outputs-1); /* other outputs */

    }

    av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f select_out:%d\n", res, select->select_out);

    if (res) {

        select->var_values[VAR_PREV_SELECTED_N]   = select->var_values[VAR_N];

        select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];

        select->var_values[VAR_PREV_SELECTED_T]   = select->var_values[VAR_T];

        select->var_values[VAR_SELECTED_N] += 1.0;

        if (inlink->type == AVMEDIA_TYPE_AUDIO)

            select->var_values[VAR_CONSUMED_SAMPLES_N] += frame->nb_samples;

    }

    select->var_values[VAR_PREV_PTS] = select->var_values[VAR_PTS];

    select->var_values[VAR_PREV_T]   = select->var_values[VAR_T];

}


static int libkvazaar_encode(AVCodecContext *avctx,

                             AVPacket *avpkt,

                             const AVFrame *frame,

                             int *got_packet_ptr)

{

    int retval = 0;

    kvz_picture *img_in = NULL;

    kvz_data_chunk *data_out = NULL;

    uint32_t len_out = 0;

    kvz_frame_info frame_info;

    LibkvazaarContext *ctx = avctx->priv_data;

    *got_packet_ptr = 0;

    if (frame) {

        int i = 0;

        av_assert0(frame->width == ctx->config->width);

        av_assert0(frame->height == ctx->config->height);

        av_assert0(frame->format == avctx->pix_fmt);

        // Allocate input picture for kvazaar.

        img_in = ctx->api->picture_alloc(frame->width, frame->height);

        if (!img_in) {

            av_log(avctx, AV_LOG_ERROR, "Failed to allocate picture.\n");

            retval = AVERROR(ENOMEM);

            goto done;

        }

        // Copy pixels from frame to img_in.

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

            uint8_t *dst = img_in->data[i];

            uint8_t *src = frame->data[i];

            int width = (i == 0) ? frame->width : (frame->width / 2);

            int height = (i == 0) ? frame->height : (frame->height / 2);

            int y = 0;

            for (y = 0; y < height; ++y) {

                memcpy(dst, src, width);

                src += frame->linesize[i];

                dst += width;

            }

        }

    }

    if (!ctx->api->encoder_encode(ctx->encoder, img_in,

                                  &data_out, &len_out,

                                  NULL, NULL,

                                  &frame_info)) {

        av_log(avctx, AV_LOG_ERROR, "Failed to encode frame.\n");

        retval = AVERROR_EXTERNAL;

        goto done;

    }

    if (data_out) {

        kvz_data_chunk *chunk = NULL;

        uint64_t written = 0;

        retval = ff_alloc_packet(avpkt, len_out);

        if (retval < 0) {

            av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n");

            goto done;

        }

        for (chunk = data_out; chunk != NULL; chunk = chunk->next) {

            av_assert0(written + chunk->len <= len_out);

            memcpy(avpkt->data + written, chunk->data, chunk->len);

            written += chunk->len;

        }

        *got_packet_ptr = 1;

        ctx->api->chunk_free(data_out);

        data_out = NULL;

        avpkt->flags = 0;

        // IRAP VCL NAL unit types span the range

        // [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].

        if (frame_info.nal_unit_type >= KVZ_NAL_BLA_W_LP &&

                frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) {

            avpkt->flags |= AV_PKT_FLAG_KEY;

        }

    }

done:

    ctx->api->picture_free(img_in);

    ctx->api->chunk_free(data_out);

    return retval;

}


static int send_extradata(APNGDemuxContext *ctx, AVPacket *pkt)

{

    if (!ctx->extra_data_updated) {

        uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, ctx->extra_data_size);

        if (!side_data)

            return AVERROR(ENOMEM);

        memcpy(side_data, ctx->extra_data, ctx->extra_data_size);

        ctx->extra_data_updated = 1;

    }

    return 0;

}


static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,

                        target_phys_addr_t ctrl_base, int it_shift)

{

    int s_ioport_ctrl, vga_io_memory;

    s->it_shift = it_shift;

    s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);

    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);

    register_savevm("vga", 0, 2, vga_save, vga_load, s);

    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);

    s->bank_offset = 0;

    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);

}


TranslationBlock *tb_gen_code(CPUState *cpu,

                              target_ulong pc, target_ulong cs_base,

                              uint32_t flags, int cflags)

{

    CPUArchState *env = cpu->env_ptr;

    TranslationBlock *tb;

    tb_page_addr_t phys_pc, phys_page2;

    target_ulong virt_page2;

    tcg_insn_unit *gen_code_buf;

    int gen_code_size, search_size;

#ifdef CONFIG_PROFILER

    int64_t ti;

#endif

    assert_memory_lock();

    phys_pc = get_page_addr_code(env, pc);

    if (use_icount && !(cflags & CF_IGNORE_ICOUNT)) {

        cflags |= CF_USE_ICOUNT;

    }

    tb = tb_alloc(pc);

    if (unlikely(!tb)) {

 buffer_overflow:

        /* flush must be done */

        tb_flush(cpu);

        mmap_unlock();

        /* Make the execution loop process the flush as soon as possible.  */

        cpu->exception_index = EXCP_INTERRUPT;

        cpu_loop_exit(cpu);

    }

    gen_code_buf = tcg_ctx.code_gen_ptr;

    tb->tc_ptr = gen_code_buf;

    tb->pc = pc;

    tb->cs_base = cs_base;

    tb->flags = flags;

    tb->cflags = cflags;

    tb->trace_vcpu_dstate = *cpu->trace_dstate;

    tb->invalid = false;

#ifdef CONFIG_PROFILER

    tcg_ctx.tb_count1++; /* includes aborted translations because of

                       exceptions */

    ti = profile_getclock();

#endif

    tcg_func_start(&tcg_ctx);

    tcg_ctx.cpu = ENV_GET_CPU(env);

    gen_intermediate_code(cpu, tb);

    tcg_ctx.cpu = NULL;

    trace_translate_block(tb, tb->pc, tb->tc_ptr);

    /* generate machine code */

    tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;

    tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;

    tcg_ctx.tb_jmp_reset_offset = tb->jmp_reset_offset;

    if (TCG_TARGET_HAS_direct_jump) {

        tcg_ctx.tb_jmp_insn_offset = tb->jmp_target_arg;

        tcg_ctx.tb_jmp_target_addr = NULL;

    } else {

        tcg_ctx.tb_jmp_insn_offset = NULL;

        tcg_ctx.tb_jmp_target_addr = tb->jmp_target_arg;

    }

#ifdef CONFIG_PROFILER

    tcg_ctx.tb_count++;

    tcg_ctx.interm_time += profile_getclock() - ti;

    tcg_ctx.code_time -= profile_getclock();

#endif

    /* ??? Overflow could be handled better here.  In particular, we

       don't need to re-do gen_intermediate_code, nor should we re-do

       the tcg optimization currently hidden inside tcg_gen_code.  All

       that should be required is to flush the TBs, allocate a new TB,

       re-initialize it per above, and re-do the actual code generation.  */

    gen_code_size = tcg_gen_code(&tcg_ctx, tb);

    if (unlikely(gen_code_size < 0)) {

        goto buffer_overflow;

    }

    search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);

    if (unlikely(search_size < 0)) {

        goto buffer_overflow;

    }

#ifdef CONFIG_PROFILER

    tcg_ctx.code_time += profile_getclock();

    tcg_ctx.code_in_len += tb->size;

    tcg_ctx.code_out_len += gen_code_size;

    tcg_ctx.search_out_len += search_size;

#endif

#ifdef DEBUG_DISAS

    if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) &&

        qemu_log_in_addr_range(tb->pc)) {

        qemu_log_lock();

        qemu_log("OUT: [size=%d]\n", gen_code_size);

        if (tcg_ctx.data_gen_ptr) {

            size_t code_size = tcg_ctx.data_gen_ptr - tb->tc_ptr;

            size_t data_size = gen_code_size - code_size;

            size_t i;

            log_disas(tb->tc_ptr, code_size);

            for (i = 0; i < data_size; i += sizeof(tcg_target_ulong)) {

                if (sizeof(tcg_target_ulong) == 8) {

                    qemu_log("0x%08" PRIxPTR ":  .quad  0x%016" PRIx64 "\n",

                             (uintptr_t)tcg_ctx.data_gen_ptr + i,

                             *(uint64_t *)(tcg_ctx.data_gen_ptr + i));

                } else {

                    qemu_log("0x%08" PRIxPTR ":  .long  0x%08x\n",

                             (uintptr_t)tcg_ctx.data_gen_ptr + i,

                             *(uint32_t *)(tcg_ctx.data_gen_ptr + i));

                }

            }

        } else {

            log_disas(tb->tc_ptr, gen_code_size);

        }

        qemu_log("\n");

        qemu_log_flush();

        qemu_log_unlock();

    }

#endif

    tcg_ctx.code_gen_ptr = (void *)

        ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size,

                 CODE_GEN_ALIGN);

    /* init jump list */

    assert(((uintptr_t)tb & 3) == 0);

    tb->jmp_list_first = (uintptr_t)tb | 2;

    tb->jmp_list_next[0] = (uintptr_t)NULL;

    tb->jmp_list_next[1] = (uintptr_t)NULL;

    /* init original jump addresses wich has been set during tcg_gen_code() */

    if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {

        tb_reset_jump(tb, 0);

    }

    if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {

        tb_reset_jump(tb, 1);

    }

    /* check next page if needed */

    virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;

    phys_page2 = -1;

    if ((pc & TARGET_PAGE_MASK) != virt_page2) {

        phys_page2 = get_page_addr_code(env, virt_page2);

    }

    /* As long as consistency of the TB stuff is provided by tb_lock in user

     * mode and is implicit in single-threaded softmmu emulation, no explicit

     * memory barrier is required before tb_link_page() makes the TB visible

     * through the physical hash table and physical page list.

     */

    tb_link_page(tb, phys_pc, phys_page2);

    return tb;

}


static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,

                                TCGv addr, int size)

{

    TCGv tmp;

    int done_label;

    int fail_label;

    /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {

         [addr] = {Rt};

         {Rd} = 0;

       } else {

         {Rd} = 1;

       } */

    fail_label = gen_new_label();

    done_label = gen_new_label();

    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);

    switch (size) {

    case 0:

        tmp = gen_ld8u(addr, IS_USER(s));

        break;

    case 1:

        tmp = gen_ld16u(addr, IS_USER(s));

        break;

    case 2:

    case 3:

        tmp = gen_ld32(addr, IS_USER(s));

        break;

    default:

        abort();

    }

    tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);

    dead_tmp(tmp);

    if (size == 3) {

        TCGv tmp2 = new_tmp();

        tcg_gen_addi_i32(tmp2, addr, 4);

        tmp = gen_ld32(tmp2, IS_USER(s));

        dead_tmp(tmp2);

        tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);

        dead_tmp(tmp);

    }

    tmp = load_reg(s, rt);

    switch (size) {

    case 0:

        gen_st8(tmp, addr, IS_USER(s));

        break;

    case 1:

        gen_st16(tmp, addr, IS_USER(s));

        break;

    case 2:

    case 3:

        gen_st32(tmp, addr, IS_USER(s));

        break;

    default:

        abort();

    }

    if (size == 3) {

        tcg_gen_addi_i32(addr, addr, 4);

        tmp = load_reg(s, rt2);

        gen_st32(tmp, addr, IS_USER(s));

    }

    tcg_gen_movi_i32(cpu_R[rd], 0);

    tcg_gen_br(done_label);

    gen_set_label(fail_label);

    tcg_gen_movi_i32(cpu_R[rd], 1);

    gen_set_label(done_label);

    tcg_gen_movi_i32(cpu_exclusive_addr, -1);

}


static void syborg_init(ram_addr_t ram_size,

                        const char *boot_device,

                        const char *kernel_filename, const char *kernel_cmdline,

                        const char *initrd_filename, const char *cpu_model)

{

    CPUState *env;

    qemu_irq *cpu_pic;

    qemu_irq pic[64];

    ram_addr_t ram_addr;

    DeviceState *dev;

    int i;

    if (!cpu_model)

        cpu_model = "cortex-a8";

    env = cpu_init(cpu_model);

    if (!env) {

        fprintf(stderr, "Unable to find CPU definition\n");

        exit(1);

    }

    /* RAM at address zero. */

    ram_addr = qemu_ram_alloc(ram_size);

    cpu_register_physical_memory(0, ram_size, ram_addr | IO_MEM_RAM);

    cpu_pic = arm_pic_init_cpu(env);

    dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,

                               cpu_pic[ARM_PIC_CPU_IRQ]);

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

        pic[i] = qdev_get_gpio_in(dev, i);

    }

    sysbus_create_simple("syborg,rtc", 0xC0001000, NULL);

    dev = qdev_create(NULL, "syborg,timer");

    qdev_prop_set_uint32(dev, "frequency", 1000000);

    qdev_init(dev);

    sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xC0002000);

    sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[1]);

    sysbus_create_simple("syborg,keyboard", 0xC0003000, pic[2]);

    sysbus_create_simple("syborg,pointer", 0xC0004000, pic[3]);

    sysbus_create_simple("syborg,framebuffer", 0xC0005000, pic[4]);

    sysbus_create_simple("syborg,serial", 0xC0006000, pic[5]);

    sysbus_create_simple("syborg,serial", 0xC0007000, pic[6]);

    sysbus_create_simple("syborg,serial", 0xC0008000, pic[7]);

    sysbus_create_simple("syborg,serial", 0xC0009000, pic[8]);

    if (nd_table[0].vlan) {

        DeviceState *dev;

        SysBusDevice *s;

        qemu_check_nic_model(&nd_table[0], "virtio");

        dev = qdev_create(NULL, "syborg,virtio-net");

        dev->nd = &nd_table[0];

        qdev_init(dev);

        s = sysbus_from_qdev(dev);

        sysbus_mmio_map(s, 0, 0xc000c000);

        sysbus_connect_irq(s, 0, pic[9]);

    }

    syborg_binfo.ram_size = ram_size;

    syborg_binfo.kernel_filename = kernel_filename;

    syborg_binfo.kernel_cmdline = kernel_cmdline;

    syborg_binfo.initrd_filename = initrd_filename;

    syborg_binfo.board_id = 0;

    arm_load_kernel(env, &syborg_binfo);

}


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

                                const uint8_t *buf, int buf_size)

{

    const uint8_t   *buf_ptr = buf, *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;

    /* parse and check the OS header */

    frame_num = bytestream_get_le32(&buf_ptr);

    word2     = bytestream_get_le32(&buf_ptr);

    check_sum = bytestream_get_le32(&buf_ptr);

    data_size = bytestream_get_le32(&buf_ptr);

    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 = buf_ptr;

    if (bytestream_get_le16(&buf_ptr) != 32) {

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

        return AVERROR_INVALIDDATA;

    }

    ctx->frame_num   =  frame_num;

    ctx->frame_flags =  bytestream_get_le16(&buf_ptr);

    ctx->data_size   = (bytestream_get_le32(&buf_ptr) + 7) >> 3;

    ctx->cb_offset   = *buf_ptr++;

    if (ctx->data_size == 16)

        return 4;

    if (ctx->data_size > buf_size)

        ctx->data_size = buf_size;

    buf_ptr += 3; // skip reserved byte and checksum

    /* check frame dimensions */

    height = bytestream_get_le16(&buf_ptr);

    width  = bytestream_get_le16(&buf_ptr);

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

        return AVERROR_INVALIDDATA;

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

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

        ctx->width  = width;

        ctx->height = height;

        free_frame_buffers(ctx);

        allocate_frame_buffers(ctx, avctx);

        avcodec_set_dimensions(avctx, width, height);

    }

    y_offset = bytestream_get_le32(&buf_ptr);

    v_offset = bytestream_get_le32(&buf_ptr);

    u_offset = bytestream_get_le32(&buf_ptr);

    /* 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(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  = buf_ptr + sizeof(uint32_t);

    if (ctx->data_size == 16) {

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

        return 16;

    }

    if (ctx->frame_flags & BS_8BIT_PEL) {

        av_log_ask_for_sample(avctx, "8-bit pixel format\n");

        return AVERROR_PATCHWELCOME;

    }

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

        av_log_ask_for_sample(avctx, "halfpel motion vectors\n");

        return AVERROR_PATCHWELCOME;

    }

    return 0;

}


static void cin_decode_rle(const unsigned char *src, int src_size,

                           unsigned char *dst, int dst_size)

{

    int len, code;

    unsigned char *dst_end       = dst + dst_size;

    const unsigned char *src_end = src + src_size;

    while (src < src_end && dst < dst_end) {

        code = *src++;

        if (code & 0x80) {

            len = code - 0x7F;

            memset(dst, *src++, FFMIN(len, dst_end - dst));

        } else {

            len = code + 1;

            memcpy(dst, src, FFMIN(len, dst_end - dst));

            src += len;

        }

        dst += len;

    }

}


BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
        BlockDriverCompletionFunc *cb, void *opaque)
{
    BlockDriver *drv = bs->drv;
    if (!drv)
        return NULL;
    return drv->bdrv_aio_flush(bs, cb, opaque);