mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
initial XvMC support
Originally committed as revision 2085 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
ff862be5ed
commit
2e7b4c8442
@ -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;
|
||||
@ -2182,6 +2202,11 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
|
||||
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;
|
||||
s1->mpeg_enc_ctx_allocated = 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;
|
||||
|
267
libavcodec/xvmcvideo.c
Normal file
267
libavcodec/xvmcvideo.c
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user