diff options
author | Ivan Kalvachev <ikalvachev@gmail.com> | 2003-07-26 01:28:49 +0000 |
---|---|---|
committer | Ivan Kalvachev <ikalvachev@gmail.com> | 2003-07-26 01:28:49 +0000 |
commit | 2e7b4c8442fd5a39c9bf78ad71b62acfaa6c2d7c (patch) | |
tree | bd0f902d7d4cc7a5ff4eae4d286bffaef1fa9148 | |
parent | ff862be5ed2d7d6799ee23e04c5fbee0c1e1f987 (diff) | |
download | ffmpeg-2e7b4c8442fd5a39c9bf78ad71b62acfaa6c2d7c.tar.gz |
initial XvMC support
Originally committed as revision 2085 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavcodec/Makefile | 2 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 3 | ||||
-rw-r--r-- | libavcodec/error_resilience.c | 5 | ||||
-rw-r--r-- | libavcodec/mpeg12.c | 59 | ||||
-rw-r--r-- | libavcodec/mpegvideo.c | 22 | ||||
-rw-r--r-- | libavcodec/xvmcvideo.c | 267 |
6 files changed, 356 insertions, 2 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 894c53aca5..49c2b62509 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -14,7 +14,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \ mpegvideo.o jrevdct.o jfdctfst.o jfdctint.o\ mpegaudio.o ac3enc.o mjpeg.o resample.o dsputil.o \ motion_est.o imgconvert.o imgresample.o \ - mpeg12.o mpegaudiodec.o pcm.o simple_idct.o \ + mpeg12.o xvmcvideo.o mpegaudiodec.o pcm.o simple_idct.o \ ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 43320e6980..c364f228da 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -96,6 +96,9 @@ void avcodec_register_all(void) #endif #endif register_avcodec(&mpeg_decoder); +#ifdef HAVE_XVMC + register_avcodec(&mpeg_xvmc_decoder); +#endif register_avcodec(&dvvideo_decoder); register_avcodec(&dvaudio_decoder); register_avcodec(&mjpeg_decoder); diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 4ac92bfd29..fd7eb37737 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -894,6 +894,10 @@ void ff_er_frame_end(MpegEncContext *s){ }else guess_mv(s); +#ifdef HAVE_XVMC + /* the filters below are not XvMC compatible, skip them */ + if(s->avctx->xvmc_acceleration) goto ec_clean; +#endif /* fill DC for inter blocks */ for(mb_y=0; mb_y<s->mb_height; mb_y++){ for(mb_x=0; mb_x<s->mb_width; mb_x++){ @@ -979,6 +983,7 @@ void ff_er_frame_end(MpegEncContext *s){ v_block_filter(s, s->current_picture.data[2], s->mb_width , s->mb_height , s->uvlinesize, 0); } +ec_clean: /* clean a few tables */ for(i=0; i<s->mb_num; i++){ const int mb_xy= s->mb_index2xy[i]; diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 62734b4778..4f007ca3ca 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -67,6 +67,11 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, int n); static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred); +#ifdef HAVE_XVMC +extern int XVMC_field_start(MpegEncContext *s, AVCodecContext *avctx); +extern int XVMC_field_end(MpegEncContext *s); +#endif + #ifdef CONFIG_ENCODERS static uint8_t (*mv_penalty)[MAX_MV*2+1]= NULL; static uint8_t fcode_tab[MAX_MV*2+1]; @@ -1875,7 +1880,13 @@ static int mpeg_decode_slice(AVCodecContext *avctx, } } } - } +#ifdef HAVE_XVMC +// MPV_frame_start will call this function too, +// but we need to call it on every field + if(s->avctx->xvmc_acceleration) + XVMC_field_start(s,avctx); +#endif + }//fi(s->first_slice) s->first_slice = 0; init_get_bits(&s->gb, *buf, buf_size*8); @@ -2020,6 +2031,10 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict) if (!s1->mpeg_enc_ctx_allocated) return 0; +#ifdef HAVE_XVMC + if(s->avctx->xvmc_acceleration) + XVMC_field_end(s); +#endif /* end of slice reached */ if (/*s->mb_y<<field_pic == s->mb_height &&*/ !s->first_field) { /* end of image */ @@ -2103,6 +2118,11 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, ); avctx->bit_rate = s->bit_rate; + //get_format() or set_video(width,height,aspect,pix_fmt); + //until then pix_fmt may be changed right after codec init + if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT ) + avctx->idct_algo = FF_IDCT_SIMPLE; + if (MPV_common_init(s) < 0) return -1; s1->mpeg_enc_ctx_allocated = 1; @@ -2181,6 +2201,11 @@ static int vcr2_init_sequence(AVCodecContext *avctx) avctx->has_b_frames= 0; //true? s->low_delay= 1; s->avctx = avctx; + + //get_format() or set_video(width,height,aspect,pix_fmt); + //until then pix_fmt may be changed right after codec init + if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT ) + avctx->idct_algo = FF_IDCT_SIMPLE; if (MPV_common_init(s) < 0) return -1; @@ -2414,3 +2439,35 @@ AVCodec mpeg_decoder = { CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED, .flush= ff_mpeg_flush, }; + +#ifdef HAVE_XVMC +static int mpeg_mc_decode_init(AVCodecContext *avctx){ + Mpeg1Context *s; + + if( !(avctx->slice_flags & SLICE_FLAG_CODED_ORDER) ) + return -1; + if( !(avctx->slice_flags & SLICE_FLAG_ALLOW_FIELD) ) + dprintf("mpeg12.c: XvMC decoder will work better if SLICE_FLAG_ALLOW_FIELD is set\n"); + + mpeg_decode_init(avctx); + s = avctx->priv_data; + + avctx->pix_fmt = PIX_FMT_XVMC_MPEG2_IDCT; + avctx->xvmc_acceleration = 1; + + return 0; +} + +AVCodec mpeg_xvmc_decoder = { + "mpegvideo_xvmc", + CODEC_TYPE_VIDEO, + CODEC_ID_MPEG2VIDEO_XVMC, + sizeof(Mpeg1Context), + mpeg_mc_decode_init, + NULL, + mpeg_decode_end, + mpeg_decode_frame, + CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED, +}; + +#endif diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 3c11646396..737cd0d1c8 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -52,6 +52,12 @@ static int dct_quantize_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, static int dct_quantize_trellis_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow); #endif //CONFIG_ENCODERS +#ifdef HAVE_XVMC +extern int XVMC_field_start(MpegEncContext*s, AVCodecContext *avctx); +extern void XVMC_field_end(MpegEncContext *s); +extern void XVMC_decode_mb(MpegEncContext *s, DCTELEM block[6][64]); +#endif + void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w)= draw_edges_c; @@ -1028,6 +1034,10 @@ alloc: }else s->dct_unquantize = s->dct_unquantize_mpeg1; +#ifdef HAVE_XVMC + if(s->avctx->xvmc_acceleration) + return XVMC_field_start(s, avctx); +#endif return 0; } @@ -1036,6 +1046,12 @@ void MPV_frame_end(MpegEncContext *s) { int i; /* draw edge for correct motion prediction if outside */ +#ifdef HAVE_XVMC +//just to make sure that all data is rendered. + if(s->avctx->xvmc_acceleration){ + XVMC_field_end(s); + }else +#endif if(s->codec_id!=CODEC_ID_SVQ1 && s->codec_id != CODEC_ID_MPEG1VIDEO){ if (s->pict_type != B_TYPE && !s->intra_only && !(s->flags&CODEC_FLAG_EMU_EDGE)) { draw_edges(s->current_picture.data[0], s->linesize , s->h_edge_pos , s->v_edge_pos , EDGE_WIDTH ); @@ -2382,6 +2398,12 @@ void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]) { int mb_x, mb_y; const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; +#ifdef HAVE_XVMC + if(s->avctx->xvmc_acceleration){ + XVMC_decode_mb(s,block); + return; + } +#endif mb_x = s->mb_x; mb_y = s->mb_y; diff --git a/libavcodec/xvmcvideo.c b/libavcodec/xvmcvideo.c new file mode 100644 index 0000000000..d6aaee4541 --- /dev/null +++ b/libavcodec/xvmcvideo.c @@ -0,0 +1,267 @@ +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <limits.h> + +//X11 include +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> +#include <X11/extensions/XvMClib.h> + +#include "xvmc_render.h" + +//avcodec include +#include "avcodec.h" +#include "dsputil.h" +#include "mpegvideo.h" + +#undef NDEBUG +#include <assert.h> + +#ifdef USE_FASTMEMCPY +#include "fastmemcpy.h" +#endif + +#ifdef HAVE_XVMC +//#include "xvmc_debug.h" + +static int calc_cbp(MpegEncContext *s, int blocknum){ +/* compute cbp */ +// for I420 bit_offset=5 +int i,cbp = 0; + for(i=0; i<blocknum; i++) { + if(s->block_last_index[i] >= 0) + cbp |= 1 << (5 - i); + } + return cbp; +} + + + +//these functions should be called on every new field or/and frame +//They should be safe if they are called few times for same field! +int XVMC_field_start(MpegEncContext*s, AVCodecContext *avctx){ +xvmc_render_state_t * render,* last, * next; + + assert(avctx != NULL); + render = (xvmc_render_state_t*)s->current_picture.data[2]; + assert(render != NULL); + + render->picture_structure = s->picture_structure; + render->flags = (s->first_field)? 0: XVMC_SECOND_FIELD; + +//make sure that all data is drawn by XVMC_end_frame + assert(render->filled_mv_blocks_num==0); + + render->p_future_surface = NULL; + render->p_past_surface = NULL; + + switch(s->pict_type){ + case I_TYPE: + return 0;// no prediction from other frames + case B_TYPE: + next = (xvmc_render_state_t*)s->next_picture.data[2]; + assert(next!=NULL); + assert(next->state & MP_XVMC_STATE_PREDICTION); + render->p_future_surface = next->p_surface; + //no return here, going to set forward prediction + case P_TYPE: + last = (xvmc_render_state_t*)s->last_picture.data[2]; + if(last == NULL)// && !s->first_field) + last = render;//predict second field from the first + assert(last->state & MP_XVMC_STATE_PREDICTION); + render->p_past_surface = last->p_surface; + return 0; + } + +return -1; +} + +void XVMC_field_end(MpegEncContext *s){ +xvmc_render_state_t * render; + render = (xvmc_render_state_t*)s->current_picture.data[2]; + assert(render != NULL); + + if(render->filled_mv_blocks_num > 0){ +// printf("xvmcvideo.c: rendering %d left blocks after last slice!!!\n",render->filled_mv_blocks_num ); + ff_draw_horiz_band(s,0,0); + } +} + +void XVMC_decode_mb(MpegEncContext *s, DCTELEM block[6][64]){ +XvMCMacroBlock * mv_block; +xvmc_render_state_t * render; +int i,cbp,blocks_per_mb; + +const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + + + if(s->encoding){ + fprintf(stderr,"XVMC doesn't support encoding!!!\n"); + assert(0); + return; + } + + //from MPV_decode_mb(), + /* update DC predictors for P macroblocks */ + if (!s->mb_intra) { + s->last_dc[0] = + s->last_dc[1] = + s->last_dc[2] = 128 << s->intra_dc_precision; + } + + //MC doesn't skip blocks + s->mb_skiped = 0; + + + // do I need to export quant when I could not perform postprocessing? + // anyway, it doesn't hurrt + s->current_picture.qscale_table[mb_xy] = s->qscale; + +//START OF XVMC specific code + render = (xvmc_render_state_t*)s->current_picture.data[2]; + assert(render!=NULL); + assert(render->magic==MP_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 ]; + +// memset(mv_block,0,sizeof(XvMCMacroBlock)); + + mv_block->x = s->mb_x; + mv_block->y = s->mb_y; + mv_block->dct_type = s->interlaced_dct;//XVMC_DCT_TYPE_FRAME/FIELD; +// mv_block->motion_type = 0; //zero to silense warnings + if(s->mb_intra){ + mv_block->macroblock_type = XVMC_MB_TYPE_INTRA;//no MC, all done + }else{ + mv_block->macroblock_type = XVMC_MB_TYPE_PATTERN; + + if(s->mv_dir & MV_DIR_FORWARD){ + mv_block->macroblock_type|= XVMC_MB_TYPE_MOTION_FORWARD; + //pmv[n][dir][xy]=mv[dir][n][xy] + mv_block->PMV[0][0][0] = s->mv[0][0][0]; + mv_block->PMV[0][0][1] = s->mv[0][0][1]; + mv_block->PMV[1][0][0] = s->mv[0][1][0]; + mv_block->PMV[1][0][1] = s->mv[0][1][1]; + } + if(s->mv_dir & MV_DIR_BACKWARD){ + mv_block->macroblock_type|=XVMC_MB_TYPE_MOTION_BACKWARD; + mv_block->PMV[0][1][0] = s->mv[1][0][0]; + mv_block->PMV[0][1][1] = s->mv[1][0][1]; + mv_block->PMV[1][1][0] = s->mv[1][1][0]; + mv_block->PMV[1][1][1] = s->mv[1][1][1]; + } + + switch(s->mv_type){ + case MV_TYPE_16X16: + mv_block->motion_type = XVMC_PREDICTION_FRAME; + break; + case MV_TYPE_16X8: + mv_block->motion_type = XVMC_PREDICTION_16x8; + break; + case MV_TYPE_FIELD: + mv_block->motion_type = XVMC_PREDICTION_FIELD; + if(s->picture_structure == PICT_FRAME){ + mv_block->PMV[0][0][1]<<=1; + mv_block->PMV[1][0][1]<<=1; + mv_block->PMV[0][1][1]<<=1; + mv_block->PMV[1][1][1]<<=1; + } + break; + case MV_TYPE_DMV: + 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][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][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][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][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 + } + break; + default: + assert(0); + } + + mv_block->motion_vertical_field_select = 0; + +//set correct field referenses + if(s->mv_type == MV_TYPE_FIELD || s->mv_type == MV_TYPE_16X8){ + if( s->field_select[0][0] ) mv_block->motion_vertical_field_select|=1; + if( s->field_select[1][0] ) mv_block->motion_vertical_field_select|=2; + if( s->field_select[0][1] ) mv_block->motion_vertical_field_select|=4; + if( s->field_select[1][1] ) mv_block->motion_vertical_field_select|=8; + } + }//!intra +//time to handle data blocks; + mv_block->index = render->next_free_data_block_num; + blocks_per_mb = 6; +/* + switch( s->chroma_format){ + case CHROMA_422: + blocks_per_mb = 8; + break; + case CHROMA_444: + blocks_per_mb = 12; + break; + } +*/ + if(s->flags & CODEC_FLAG_GRAY){ + if(s->mb_intra){//intra frames are alwasy full chroma block + memset(block[4],0,sizeof(short)*8*8);//so we need to clear them + memset(block[5],0,sizeof(short)*8*8); + if(!render->unsigned_intra) + block[4][0] = block[5][0] = 1<<10; + } + else + blocks_per_mb = 4;//Luminance blocks only + }; + cbp = calc_cbp(s,blocks_per_mb); + mv_block->coded_block_pattern = cbp; + if(cbp == 0) + mv_block->macroblock_type &= ~XVMC_MB_TYPE_PATTERN; + + for(i=0; i<blocks_per_mb; i++){ + if(s->block_last_index[i] >= 0){ + // i do not have unsigned_intra MOCO to test, hope it is OK + if( (s->mb_intra) && ( render->idct || (!render->idct && !render->unsigned_intra)) ) + block[i][0]-=1<<10; + if(!render->idct){ + s->dsp.idct(block[i]); + //!!TODO!clip!!! + } +//TODO:avoid block copy by modifying s->block pointer + memcpy(&render->data_blocks[(render->next_free_data_block_num++)*64], + block[i],sizeof(short)*8*8); + } + } + render->filled_mv_blocks_num++; + + 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); + + + if(render->filled_mv_blocks_num >= render->total_number_of_mv_blocks) + ff_draw_horiz_band(s,0,0); + +// DumpRenderInfo(render); +// DumpMBlockInfo(mv_block); + +} + +#endif |