aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Kalvachev <ikalvachev@gmail.com>2003-07-26 01:28:49 +0000
committerIvan Kalvachev <ikalvachev@gmail.com>2003-07-26 01:28:49 +0000
commit2e7b4c8442fd5a39c9bf78ad71b62acfaa6c2d7c (patch)
treebd0f902d7d4cc7a5ff4eae4d286bffaef1fa9148
parentff862be5ed2d7d6799ee23e04c5fbee0c1e1f987 (diff)
downloadffmpeg-2e7b4c8442fd5a39c9bf78ad71b62acfaa6c2d7c.tar.gz
initial XvMC support
Originally committed as revision 2085 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/allcodecs.c3
-rw-r--r--libavcodec/error_resilience.c5
-rw-r--r--libavcodec/mpeg12.c59
-rw-r--r--libavcodec/mpegvideo.c22
-rw-r--r--libavcodec/xvmcvideo.c267
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