Originally committed as revision 2085 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
@@ -14,7 +14,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \ | |||||
mpegvideo.o jrevdct.o jfdctfst.o jfdctint.o\ | mpegvideo.o jrevdct.o jfdctfst.o jfdctint.o\ | ||||
mpegaudio.o ac3enc.o mjpeg.o resample.o dsputil.o \ | mpegaudio.o ac3enc.o mjpeg.o resample.o dsputil.o \ | ||||
motion_est.o imgconvert.o imgresample.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 \ | 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 \ | 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 | 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 | ||||
#endif | #endif | ||||
register_avcodec(&mpeg_decoder); | register_avcodec(&mpeg_decoder); | ||||
#ifdef HAVE_XVMC | |||||
register_avcodec(&mpeg_xvmc_decoder); | |||||
#endif | |||||
register_avcodec(&dvvideo_decoder); | register_avcodec(&dvvideo_decoder); | ||||
register_avcodec(&dvaudio_decoder); | register_avcodec(&dvaudio_decoder); | ||||
register_avcodec(&mjpeg_decoder); | register_avcodec(&mjpeg_decoder); | ||||
@@ -894,6 +894,10 @@ void ff_er_frame_end(MpegEncContext *s){ | |||||
}else | }else | ||||
guess_mv(s); | 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 */ | /* fill DC for inter blocks */ | ||||
for(mb_y=0; mb_y<s->mb_height; mb_y++){ | for(mb_y=0; mb_y<s->mb_height; mb_y++){ | ||||
for(mb_x=0; mb_x<s->mb_width; mb_x++){ | 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); | v_block_filter(s, s->current_picture.data[2], s->mb_width , s->mb_height , s->uvlinesize, 0); | ||||
} | } | ||||
ec_clean: | |||||
/* clean a few tables */ | /* clean a few tables */ | ||||
for(i=0; i<s->mb_num; i++){ | for(i=0; i<s->mb_num; i++){ | ||||
const int mb_xy= s->mb_index2xy[i]; | const int mb_xy= s->mb_index2xy[i]; | ||||
@@ -67,6 +67,11 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s, | |||||
int n); | int n); | ||||
static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred); | 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 | #ifdef CONFIG_ENCODERS | ||||
static uint8_t (*mv_penalty)[MAX_MV*2+1]= NULL; | static uint8_t (*mv_penalty)[MAX_MV*2+1]= NULL; | ||||
static uint8_t fcode_tab[MAX_MV*2+1]; | 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; | s->first_slice = 0; | ||||
init_get_bits(&s->gb, *buf, buf_size*8); | 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) | if (!s1->mpeg_enc_ctx_allocated) | ||||
return 0; | return 0; | ||||
#ifdef HAVE_XVMC | |||||
if(s->avctx->xvmc_acceleration) | |||||
XVMC_field_end(s); | |||||
#endif | |||||
/* end of slice reached */ | /* end of slice reached */ | ||||
if (/*s->mb_y<<field_pic == s->mb_height &&*/ !s->first_field) { | if (/*s->mb_y<<field_pic == s->mb_height &&*/ !s->first_field) { | ||||
/* end of image */ | /* end of image */ | ||||
@@ -2103,6 +2118,11 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx, | |||||
); | ); | ||||
avctx->bit_rate = s->bit_rate; | 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) | if (MPV_common_init(s) < 0) | ||||
return -1; | return -1; | ||||
s1->mpeg_enc_ctx_allocated = 1; | s1->mpeg_enc_ctx_allocated = 1; | ||||
@@ -2181,6 +2201,11 @@ static int vcr2_init_sequence(AVCodecContext *avctx) | |||||
avctx->has_b_frames= 0; //true? | avctx->has_b_frames= 0; //true? | ||||
s->low_delay= 1; | s->low_delay= 1; | ||||
s->avctx = avctx; | 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) | if (MPV_common_init(s) < 0) | ||||
return -1; | return -1; | ||||
@@ -2414,3 +2439,35 @@ AVCodec mpeg_decoder = { | |||||
CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED, | CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED, | ||||
.flush= ff_mpeg_flush, | .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); | static int dct_quantize_trellis_c(MpegEncContext *s, DCTELEM *block, int n, int qscale, int *overflow); | ||||
#endif //CONFIG_ENCODERS | #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; | void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, int w)= draw_edges_c; | ||||
@@ -1028,6 +1034,10 @@ alloc: | |||||
}else | }else | ||||
s->dct_unquantize = s->dct_unquantize_mpeg1; | s->dct_unquantize = s->dct_unquantize_mpeg1; | ||||
#ifdef HAVE_XVMC | |||||
if(s->avctx->xvmc_acceleration) | |||||
return XVMC_field_start(s, avctx); | |||||
#endif | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -1036,6 +1046,12 @@ void MPV_frame_end(MpegEncContext *s) | |||||
{ | { | ||||
int i; | int i; | ||||
/* draw edge for correct motion prediction if outside */ | /* 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->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)) { | 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 ); | 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; | int mb_x, mb_y; | ||||
const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; | 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_x = s->mb_x; | ||||
mb_y = s->mb_y; | mb_y = s->mb_y; | ||||
@@ -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 |