Commit 2e7b4c84 authored by Ivan Kalvachev's avatar Ivan Kalvachev

initial XvMC support

Originally committed as revision 2085 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent ff862be5
......@@ -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
......
......@@ -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);
......
......@@ -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];
......
......@@ -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
......@@ -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;
......
#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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment