X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmpegvideo_xvmc.c;h=e65431114d0d8b1b5ba64b47fd4b56828e2412bc;hb=1fcef40847b9beab5b1979c10efd78aa1094dbe7;hp=caf9a0741a92d496789efcd371d3c5ddeb4de759;hpb=81189e4ff61b260178b38f337ef17d8d9ddeb644;p=ffmpeg diff --git a/libavcodec/mpegvideo_xvmc.c b/libavcodec/mpegvideo_xvmc.c index caf9a0741a9..e65431114d0 100644 --- a/libavcodec/mpegvideo_xvmc.c +++ b/libavcodec/mpegvideo_xvmc.c @@ -29,26 +29,32 @@ #include #include "xvmc.h" - -//set s->block +#include "xvmc_internal.h" + +/** + * Initializes the block field of the MpegEncContext pointer passed as + * parameter after making sure that the data is not corrupted. + * In order to implement something like direct rendering instead of decodeing + * coefficients in s->blocks and then copy them, do that directly + * into the data_blocks array provided by xvmc. + */ void ff_xvmc_init_block(MpegEncContext *s) { - struct xvmc_render_state *render; - render = (struct xvmc_render_state*)s->current_picture.data[2]; - assert(render); - if (!render || render->magic != AV_XVMC_RENDER_MAGIC) { - assert(0); - return; // make sure that this is a render packet - } + struct xvmc_pix_fmt *render = (struct xvmc_pix_fmt*)s->current_picture.data[2]; + assert(render && render->xvmc_id == AV_XVMC_RENDER_MAGIC); + s->block = (DCTELEM *)(render->data_blocks + render->next_free_data_block_num * 64); } +/** + * Fill individual block pointers, so there are no gaps in the data_block array + * in case not all blocks in MB are coded. + */ void ff_xvmc_pack_pblocks(MpegEncContext *s, int cbp) { - int i, j; + int i, j = 0; const int mb_block_count = 4 + (1 << s->chroma_format); - j = 0; cbp <<= 12-mb_block_count; for (i = 0; i < mb_block_count; i++) { if (cbp & (1 << 11)) @@ -59,44 +65,58 @@ void ff_xvmc_pack_pblocks(MpegEncContext *s, int cbp) } } -// These functions should be called on every new field and/or frame. -// They should be safe if they are called a few times for the same field! +/** + * Find and store the surfaces that are used as reference frames. + * This function should be called for every new field and/or frame. + * It should be safe to call the function a few times for the same field. + */ int ff_xvmc_field_start(MpegEncContext*s, AVCodecContext *avctx) { - struct xvmc_render_state *render, *last, *next; + struct xvmc_pix_fmt *last, *next, *render = (struct xvmc_pix_fmt*)s->current_picture.data[2]; + const int mb_block_count = 4 + (1 << s->chroma_format); assert(avctx); - - render = (struct xvmc_render_state*)s->current_picture.data[2]; - assert(render); - if (!render || render->magic != AV_XVMC_RENDER_MAGIC) + if (!render || render->xvmc_id != AV_XVMC_RENDER_MAGIC || + !render->data_blocks || !render->mv_blocks) { + av_log(avctx, AV_LOG_ERROR, + "Render token doesn't look as expected.\n"); return -1; // make sure that this is a render packet + } + + if (render->filled_mv_blocks_num) { + av_log(avctx, AV_LOG_ERROR, + "Rendering surface contains %i unprocessed blocks.\n", + render->filled_mv_blocks_num); + return -1; + } + if (render->total_number_of_mv_blocks < 1 || + render->total_number_of_data_blocks < mb_block_count) { + av_log(avctx, AV_LOG_ERROR, + "Rendering surface doesn't provide enough block structures to work with.\n"); + return -1; + } render->picture_structure = s->picture_structure; render->flags = s->first_field ? 0 : XVMC_SECOND_FIELD; - - assert(render->filled_mv_blocks_num == 0); - - render->p_future_surface = NULL; - render->p_past_surface = NULL; + render->p_future_surface = NULL; + render->p_past_surface = NULL; switch(s->pict_type) { case FF_I_TYPE: return 0; // no prediction from other frames case FF_B_TYPE: - next = (struct xvmc_render_state*)s->next_picture.data[2]; - assert(next); + next = (struct xvmc_pix_fmt*)s->next_picture.data[2]; if (!next) return -1; - if (next->magic != AV_XVMC_RENDER_MAGIC) + if (next->xvmc_id != AV_XVMC_RENDER_MAGIC) return -1; render->p_future_surface = next->p_surface; // no return here, going to set forward prediction case FF_P_TYPE: - last = (struct xvmc_render_state*)s->last_picture.data[2]; + last = (struct xvmc_pix_fmt*)s->last_picture.data[2]; if (!last) last = render; // predict second field from the first - if (last->magic != AV_XVMC_RENDER_MAGIC) + if (last->xvmc_id != AV_XVMC_RENDER_MAGIC) return -1; render->p_past_surface = last->p_surface; return 0; @@ -105,20 +125,29 @@ int ff_xvmc_field_start(MpegEncContext*s, AVCodecContext *avctx) return -1; } +/** + * Complete frame/field rendering by passing any remaining blocks. + * Normally ff_draw_horiz_band() is called on each slice, however + * there may be some remaining blocks, for example put by error_resilience. + * It should be safe to call the function a few times for the same field. + */ void ff_xvmc_field_end(MpegEncContext *s) { - struct xvmc_render_state *render; - render = (struct xvmc_render_state*)s->current_picture.data[2]; + struct xvmc_pix_fmt *render = (struct xvmc_pix_fmt*)s->current_picture.data[2]; assert(render); if (render->filled_mv_blocks_num > 0) - ff_draw_horiz_band(s,0,0); + ff_draw_horiz_band(s, 0, 0); } +/** + * Synthesize the data needed by XvMC to render one macroblock of data. + * Fill all relevent fields, if necessery do IDCT. + */ void ff_xvmc_decode_mb(MpegEncContext *s) { XvMCMacroBlock *mv_block; - struct xvmc_render_state *render; + struct xvmc_pix_fmt *render; int i, cbp, blocks_per_mb; const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; @@ -145,14 +174,14 @@ void ff_xvmc_decode_mb(MpegEncContext *s) s->current_picture.qscale_table[mb_xy] = s->qscale; // start of XVMC-specific code - render = (struct xvmc_render_state*)s->current_picture.data[2]; + render = (struct xvmc_pix_fmt*)s->current_picture.data[2]; assert(render); - assert(render->magic == AV_XVMC_RENDER_MAGIC); + assert(render->xvmc_id == AV_XVMC_RENDER_MAGIC); assert(render->mv_blocks); // take the next free macroblock mv_block = &render->mv_blocks[render->start_mv_blocks_num + - render->filled_mv_blocks_num ]; + render->filled_mv_blocks_num]; mv_block->x = s->mb_x; mv_block->y = s->mb_y; @@ -178,7 +207,7 @@ void ff_xvmc_decode_mb(MpegEncContext *s) mv_block->PMV[1][1][1] = s->mv[1][1][1]; } - switch(s->mv_type){ + switch(s->mv_type) { case MV_TYPE_16X16: mv_block->motion_type = XVMC_PREDICTION_FRAME; break; @@ -198,21 +227,21 @@ void ff_xvmc_decode_mb(MpegEncContext *s) mv_block->motion_type = XVMC_PREDICTION_DUAL_PRIME; if (s->picture_structure == PICT_FRAME) { - mv_block->PMV[0][0][0] = s->mv[0][0][0]; // top from top + mv_block->PMV[0][0][0] = s->mv[0][0][0]; // top from top mv_block->PMV[0][0][1] = s->mv[0][0][1] << 1; - mv_block->PMV[0][1][0] = s->mv[0][0][0]; // bottom from bottom + mv_block->PMV[0][1][0] = s->mv[0][0][0]; // bottom from bottom mv_block->PMV[0][1][1] = s->mv[0][0][1] << 1; - mv_block->PMV[1][0][0] = s->mv[0][2][0]; // dmv00, top from bottom + mv_block->PMV[1][0][0] = s->mv[0][2][0]; // dmv00, top from bottom mv_block->PMV[1][0][1] = s->mv[0][2][1] << 1; // dmv01 - mv_block->PMV[1][1][0] = s->mv[0][3][0]; // dmv10, bottom from top + mv_block->PMV[1][1][0] = s->mv[0][3][0]; // dmv10, bottom from top mv_block->PMV[1][1][1] = s->mv[0][3][1] << 1; // dmv11 } else { - mv_block->PMV[0][1][0] = s->mv[0][2][0]; // dmv00 - mv_block->PMV[0][1][1] = s->mv[0][2][1]; // dmv01 + mv_block->PMV[0][1][0] = s->mv[0][2][0]; // dmv00 + mv_block->PMV[0][1][1] = s->mv[0][2][1]; // dmv01 } break; default: @@ -246,15 +275,15 @@ void ff_xvmc_decode_mb(MpegEncContext *s) } if (s->flags & CODEC_FLAG_GRAY) { - if (s->mb_intra) { // intra frames are always full chroma blocks + if (s->mb_intra) { // intra frames are always full chroma blocks for (i = 4; i < blocks_per_mb; i++) { - memset(s->pblocks[i], 0, sizeof(short)*8*8); // so we need to clear them + memset(s->pblocks[i], 0, sizeof(short)*64); // so we need to clear them if (!render->unsigned_intra) s->pblocks[i][0] = 1 << 10; } } else { cbp &= 0xf << (blocks_per_mb - 4); - blocks_per_mb = 4; // luminance blocks only + blocks_per_mb = 4; // luminance blocks only } } mv_block->coded_block_pattern = cbp; @@ -276,7 +305,7 @@ void ff_xvmc_decode_mb(MpegEncContext *s) // copy blocks only if the codec doesn't support pblocks reordering if (s->avctx->xvmc_acceleration == 1) { memcpy(&render->data_blocks[render->next_free_data_block_num*64], - s->pblocks[i],sizeof(short)*8*8); + s->pblocks[i], sizeof(short)*64); } render->next_free_data_block_num++; } @@ -285,8 +314,11 @@ void ff_xvmc_decode_mb(MpegEncContext *s) assert(render->filled_mv_blocks_num <= render->total_number_of_mv_blocks); assert(render->next_free_data_block_num <= render->total_number_of_data_blocks); + /* The above conditions should not be able to fail as long as this function + * is used and the following 'if ()' automatically calls a callback to free + * blocks. */ - if (render->filled_mv_blocks_num >= render->total_number_of_mv_blocks) + if (render->filled_mv_blocks_num == render->total_number_of_mv_blocks) ff_draw_horiz_band(s, 0, 0); }