changeset 10362:8e3e884ec8a4

xvmc support
author iive
date Tue, 01 Jul 2003 22:05:46 +0000
parents 9f97e3bd0e04
children 3c7db8070985
files libmpcodecs/vd_ffmpeg.c
diffstat 1 files changed, 178 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/vd_ffmpeg.c	Tue Jul 01 22:02:17 2003 +0000
+++ b/libmpcodecs/vd_ffmpeg.c	Tue Jul 01 22:05:46 2003 +0000
@@ -47,6 +47,15 @@
 #define PIX_FMT_RGBA32 PIX_FMT_BGRA32
 #endif
 
+//!!TODO!! when ffmpeg is patched set correct version number
+#if LIBAVCODEC_BUILD < 4669
+#undef HAVE_XVMC
+#endif
+
+#ifdef HAVE_XVMC
+#include "xvmc_render.h"
+#endif
+
 int avcodec_inited=0;
 
 #if defined(FF_POSTPROCESS) && defined(MBR)
@@ -79,6 +88,14 @@
 static int get_buffer(AVCodecContext *avctx, AVFrame *pic);
 static void release_buffer(AVCodecContext *avctx, AVFrame *pic);
 
+#ifdef HAVE_XVMC
+static int mc_get_buffer(AVCodecContext *avctx, AVFrame *pic);
+static void mc_release_buffer(AVCodecContext *avctx, AVFrame *pic);
+static void mc_render_slice(struct AVCodecContext *s,
+                	uint8_t **src, int linesize,
+                	int y, int width, int height);
+#endif
+
 static int lavc_param_workaround_bugs= FF_BUG_AUTODETECT;
 static int lavc_param_error_resilience=2;
 static int lavc_param_error_concealment=3;
@@ -106,9 +123,15 @@
     AVCodecContext *avctx = ctx->avctx;
     switch(cmd){
     case VDCTRL_QUERY_FORMAT:
-	if( (*((int*)arg)) == ctx->best_csp ) return CONTROL_TRUE;//supported
+        {
+            int format =(*((int*)arg));
+	    if( format == ctx->best_csp ) return CONTROL_TRUE;//supported
+#ifdef HAVE_XVMC
+	    if( (avctx->pix_fmt == PIX_FMT_XVMC) && IMGFMT_IS_XVMC(format) ) 
+                return CONTROL_TRUE;
+#endif
 	// possible conversions:
-	switch( (*((int*)arg)) ){
+	    switch( format ){
         case IMGFMT_YV12:
         case IMGFMT_IYUV:
         case IMGFMT_I420:
@@ -119,6 +142,7 @@
 	}
         return CONTROL_FALSE;
     }
+    }
     return CONTROL_UNKNOWN;
 }
 
@@ -164,6 +188,17 @@
     ctx->avctx = avcodec_alloc_context();
     avctx = ctx->avctx;
 
+#ifdef HAVE_XVMC
+    if(lavc_codec->id == CODEC_ID_MPEG2VIDEO_XVMC){
+        printf("vd_ffmpeg: XVMC accelerated MPEG2\n");
+        assert(ctx->do_dr1);//these are must to!
+        assert(ctx->do_slices); //it is (vo_)ffmpeg bug if this fails
+        avctx->flags|= CODEC_FLAG_EMU_EDGE;//do i need that??!!
+        avctx->get_buffer= mc_get_buffer;
+        avctx->release_buffer= mc_release_buffer;
+	avctx->draw_horiz_band = mc_render_slice;
+    }else
+#endif
     if(ctx->do_dr1){
         avctx->flags|= CODEC_FLAG_EMU_EDGE; 
         avctx->get_buffer= get_buffer;
@@ -359,6 +394,11 @@
 	case PIX_FMT_YUV422:  ctx->best_csp=IMGFMT_YUY2;break; //huffyuv perhaps in the future
 	case PIX_FMT_RGB24 :  ctx->best_csp=IMGFMT_BGR24;break; //huffyuv
 	case PIX_FMT_RGBA32:  ctx->best_csp=IMGFMT_BGR32;break; //huffyuv
+#ifdef HAVE_XVMC
+	case PIX_FMT_XVMC: //ctx->best_csp=IMGFMT_XVMC_MPEG2;
+	   ctx->best_csp=sh->codec->outfmt[sh->outfmtidx];//!!maybe!!??
+           break;
+#endif
 	default:
 	    ctx->best_csp=0;
 	}
@@ -527,6 +567,11 @@
 
     if(len<=0) return NULL; // skipped frame
 
+#ifdef HAVE_XVMC
+// in fact if(!dr1) should be the only condition, but this way we hide an 
+//ffmpeg interlace (mpeg2) bug. use -noslices to avoid it.
+    if( (avctx->pix_fmt != PIX_FMT_XVMC) )// && (!dr1) )
+#endif
     avctx->draw_horiz_band=NULL;
     avctx->opaque=sh;
     if(ctx->vo_inited && !(flags&3) && !dr1){
@@ -683,4 +728,135 @@
     return mpi;
 }
 
+#ifdef HAVE_XVMC
+static int mc_get_buffer(AVCodecContext *avctx, AVFrame *pic){
+    sh_video_t * sh = avctx->opaque;
+    vd_ffmpeg_ctx *ctx = sh->context;
+    mp_image_t* mpi=NULL;
+    xvmc_render_state_t * render;
+    int flags= MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_PREFER_ALIGNED_STRIDE| 
+               MP_IMGFLAG_DRAW_CALLBACK;
+    
+//  printf("vd_ffmpeg::mc_get_buffer (xvmc) %d %d %d\n", pic->reference, ctx->ip_count, ctx->b_count);
+    if(avctx->pix_fmt != PIX_FMT_XVMC){
+        printf("vd_ffmpeg::mc_get_buffer should work only with XVMC format!!!");
+        assert(0);
+        exit(1);
+    }
+    assert(avctx->draw_horiz_band == mc_render_slice);
+    assert(avctx->release_buffer == mc_release_buffer);
+    if(verbose > 4)
+        printf("vd_ffmpeg::mc_get_buffer\n");
+    if(init_vo(sh)<0){
+        printf("vd_ffmpeg: Unexpected init_vo error\n");
+        exit(1);
+    }
+
+
+
+    if(!pic->reference){
+        ctx->b_count++;
+    }else{
+        ctx->ip_count++;
+        flags|= MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE;
+    }
+
+    mpi= mpcodecs_get_image(sh, MP_IMGTYPE_IPB,flags ,
+                            avctx->width, avctx->height);
+    if(mpi==NULL){
+        printf("Unrecoverable error, render buffers not taken\n");
+        assert(0);
+        exit(1);
+    };
+    
+    if( (mpi->flags & MP_IMGFLAG_DIRECT) == 0){
+        printf("Only buffers allocated by vo_xvmc allowed\n");
+        assert(0);
+        exit(1);
+    }
+    
+    pic->data[0]= mpi->planes[0];
+    pic->data[1]= mpi->planes[1];
+    pic->data[2]= mpi->planes[2];
+
+
+    /* Note, some (many) codecs in libavcodec must have stride1==stride2 && no changes between frames
+     * lavc will check that and die with an error message, if its not true
+     */
+    pic->linesize[0]= mpi->stride[0];
+    pic->linesize[1]= mpi->stride[1];
+    pic->linesize[2]= mpi->stride[2];
+
+    pic->opaque = mpi;
+
+    if(pic->reference){
+    //I or P frame
+        pic->age= ctx->ip_age[0];
+        
+        ctx->ip_age[0]= ctx->ip_age[1]+1;
+        ctx->ip_age[1]= 1;
+        ctx->b_age++;
+    }else{
+    //B frame
+        pic->age= ctx->b_age;
+    
+        ctx->ip_age[0]++;
+        ctx->ip_age[1]++;
+        ctx->b_age=1;
+    }
+#if LIBAVCODEC_BUILD >= 4644
+    pic->type= FF_BUFFER_TYPE_USER;
 #endif
+    render=(xvmc_render_state_t*)mpi->priv;//same as data[2]
+    assert(render != 0);
+    assert(render->magic == MP_XVMC_RENDER_MAGIC);
+    render->state |= MP_XVMC_STATE_PREDICTION;
+    return 0;
+}
+
+
+static void mc_release_buffer(AVCodecContext *avctx, AVFrame *pic){
+    mp_image_t* mpi= pic->opaque;
+    sh_video_t * sh = avctx->opaque;
+    vd_ffmpeg_ctx *ctx = sh->context;
+    xvmc_render_state_t * render;
+    int i;
+
+
+    if(ctx->ip_count <= 2 && ctx->b_count<=1){
+        if(mpi->flags&MP_IMGFLAG_PRESERVE)
+            ctx->ip_count--;
+        else
+            ctx->b_count--;
+    }
+
+//printf("R%X %X\n", pic->linesize[0], pic->data[0]);
+//mark the surface as not requared for prediction
+    render=(xvmc_render_state_t*)pic->data[2];//same as mpi->priv
+    assert(render!=NULL);
+    assert(render->magic==MP_XVMC_RENDER_MAGIC);
+    render->state&=~MP_XVMC_STATE_PREDICTION;
+    if(verbose > 4)
+        printf("vd_ffmpeg::mc_release buffer (render=%p)\n",render);
+    for(i=0; i<4; i++){
+        pic->data[i]= NULL;
+    }
+}
+
+static void mc_render_slice(struct AVCodecContext *s,
+                	uint8_t **src, int linesize,
+                	int y, int width, int height){
+
+    sh_video_t * sh = s->opaque;
+    int stride[3];
+    
+    assert(linesize==0);
+
+    stride[0]=stride[1]=stride[2]=linesize;
+    mpcodecs_draw_slice (sh,src, stride, width, height, 0, y);
+
+}
+
+#endif // HAVE_XVMC
+
+#endif