view libmpcodecs/ve_lavc.c @ 6110:7bea806b9c5f

Improvment for spu subtitles. Removed the integreted spudec in vobsub. Various cleanup/bugfix in vobsub (no more auto palette when a true one is here) HW spu rendering moved in spudec because we first need to reassable the packet before sending them to the hw. Spudec is now created only if nedded.
author albeu
date Fri, 17 May 2002 23:47:27 +0000
parents e8f6f477aad0
children ea6b20e70ac5
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../config.h"

#ifdef USE_LIBAVCODEC

#include "../mp_msg.h"
#include "../help_mp.h"

#include "codec-cfg.h"
#include "stream.h"
#include "demuxer.h"
#include "stheader.h"

#include "aviwrite.h"

#include "img_format.h"
#include "mp_image.h"
#include "vf.h"

#include "divx4_vbr.h"

extern int pass;
extern char* passtmpfile;

//===========================================================================//

#ifdef USE_LIBAVCODEC_SO
#include <libffmpeg/avcodec.h>
#else
#include "libavcodec/avcodec.h"
#endif

#if LIBAVCODEC_BUILD < 4601
#error your version of libavcodec is too old, get a newer one, and dont send a bugreport, THIS IS NO BUG
#endif

extern int avcodec_inited;

/* video options */
static char *lavc_param_vcodec = NULL;
static int lavc_param_vbitrate = -1;
static int lavc_param_vrate_tolerance = 1024*8;
static int lavc_param_vhq = 0; /* default is realtime encoding */
static int lavc_param_v4mv = 0;
static int lavc_param_vme = 4;
static int lavc_param_vqscale = 0;
static int lavc_param_vqmin = 3;
static int lavc_param_vqmax = 15;
static int lavc_param_vqdiff = 3;
static float lavc_param_vqcompress = 0.5;
static float lavc_param_vqblur = 0.5;
static float lavc_param_vb_qfactor = 2.0;
static int lavc_param_vmax_b_frames = 0;
static int lavc_param_keyint = -1;
static int lavc_param_vpass = 0;
static int lavc_param_vrc_strategy = 2;
static int lavc_param_vb_strategy = 0;

#include "cfgparser.h"

#ifdef USE_LIBAVCODEC
struct config lavcopts_conf[]={
	{"vcodec", &lavc_param_vcodec, CONF_TYPE_STRING, 0, 0, 0, NULL},
	{"vbitrate", &lavc_param_vbitrate, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
	{"vratetol", &lavc_param_vrate_tolerance, CONF_TYPE_INT, CONF_RANGE, 4, 24000000, NULL},
	{"vhq", &lavc_param_vhq, CONF_TYPE_FLAG, 0, 0, 1, NULL},
	{"v4mv", &lavc_param_v4mv, CONF_TYPE_FLAG, 0, 0, 1, NULL},
	{"vme", &lavc_param_vme, CONF_TYPE_INT, CONF_RANGE, 0, 5, NULL},
	{"vqscale", &lavc_param_vqscale, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL},
	{"vqmin", &lavc_param_vqmin, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL},
	{"vqmax", &lavc_param_vqmax, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL},
	{"vqdiff", &lavc_param_vqdiff, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL},
	{"vqcomp", &lavc_param_vqcompress, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 1.0, NULL},
	{"vqblur", &lavc_param_vqblur, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 1.0, NULL},
	{"vb_qfactor", &lavc_param_vb_qfactor, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 31.0, NULL},
	{"vmax_b_frames", &lavc_param_vmax_b_frames, CONF_TYPE_INT, CONF_RANGE, 0, FF_MAX_B_FRAMES, NULL},
	{"vpass", &lavc_param_vpass, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
	{"vrc_strategy", &lavc_param_vrc_strategy, CONF_TYPE_INT, CONF_RANGE, 0, 2, NULL},
	{"vb_strategy", &lavc_param_vb_strategy, CONF_TYPE_INT, CONF_RANGE, 0, 1, NULL},
	{"keyint", &lavc_param_keyint, CONF_TYPE_INT, 0, 0, 0, NULL},
	{NULL, NULL, 0, 0, 0, 0, NULL}
};
#endif

struct vf_priv_s {
    aviwrite_stream_t* mux;
    AVCodecContext context;
    AVCodec *codec;
};

#define mux_v (vf->priv->mux)
#define lavc_venc_context (vf->priv->context)

static int config(struct vf_instance_s* vf,
        int width, int height, int d_width, int d_height,
	unsigned int flags, unsigned int outfmt){

    mux_v->bih->biWidth=width;
    mux_v->bih->biHeight=height;
    mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8);

    memset(&lavc_venc_context, 0, sizeof(lavc_venc_context));

    printf("videocodec: libavcodec (%dx%d fourcc=%x [%.4s])\n",
	mux_v->bih->biWidth, mux_v->bih->biHeight, mux_v->bih->biCompression,
	    (char *)&mux_v->bih->biCompression);

    lavc_venc_context.width = width;
    lavc_venc_context.height = height;
    if (lavc_param_vbitrate > 16000) /* != -1 */
	lavc_venc_context.bit_rate = lavc_param_vbitrate;
    else if (lavc_param_vbitrate >= 0) /* != -1 */
	lavc_venc_context.bit_rate = lavc_param_vbitrate*1000;
    else
	lavc_venc_context.bit_rate = 800000; /* default */
    lavc_venc_context.bit_rate_tolerance= lavc_param_vrate_tolerance*1000;
    lavc_venc_context.frame_rate = (float)mux_v->h.dwRate/mux_v->h.dwScale * FRAME_RATE_BASE;
    lavc_venc_context.qmin= lavc_param_vqmin;
    lavc_venc_context.qmax= lavc_param_vqmax;
    lavc_venc_context.max_qdiff= lavc_param_vqdiff;
    lavc_venc_context.qcompress= lavc_param_vqcompress;
    lavc_venc_context.qblur= lavc_param_vqblur;
    lavc_venc_context.max_b_frames= lavc_param_vmax_b_frames;
    lavc_venc_context.b_quant_factor= lavc_param_vb_qfactor;
    lavc_venc_context.rc_strategy= lavc_param_vrc_strategy;
    lavc_venc_context.b_frame_strategy= lavc_param_vb_strategy;
    
    /* keyframe interval */
    if (lavc_param_keyint >= 0) /* != -1 */
	lavc_venc_context.gop_size = lavc_param_keyint;
    else
	lavc_venc_context.gop_size = 250; /* default */

    if (lavc_param_vhq)
    {
	printf("High quality encoding selected (non real time)!\n");
	lavc_venc_context.flags = CODEC_FLAG_HQ;
    }
    else
	lavc_venc_context.flags = 0;

     /* 4mv is currently buggy with B frames */
    if (lavc_param_vmax_b_frames > 0 && lavc_param_v4mv) {
        printf("4MV with B-Frames not yet supported -> 4MV disabled\n");
        lavc_param_v4mv = 0;
    }

    lavc_venc_context.flags|= lavc_param_v4mv ? CODEC_FLAG_4MV : 0;

    /* lavc internal 2pass bitrate control */
    if(lavc_param_vpass==1)
        lavc_venc_context.flags|= CODEC_FLAG_PASS1;
    else if(lavc_param_vpass==2)
        lavc_venc_context.flags|= CODEC_FLAG_PASS2;

#ifdef ME_ZERO
    // workaround Juanjo's stupid incompatible change:
    motion_estimation_method = lavc_param_vme;
#else
    lavc_venc_context.me_method = ME_ZERO+lavc_param_vme;
#endif

    /* fixed qscale :p */
    if (lavc_param_vqscale)
    {
	printf("Using constant qscale = %d (VBR)\n", lavc_param_vqscale);
	lavc_venc_context.flags |= CODEC_FLAG_QSCALE;
	lavc_venc_context.quality = lavc_param_vqscale;
    }

    switch(pass){
    case 1:
	if (VbrControl_init_2pass_vbr_analysis(passtmpfile, 5) == -1){
	    mp_msg(MSGT_MENCODER,MSGL_ERR,"2pass failed: filename=%s\n", passtmpfile);
	    pass=0;
	}
	break;
    case 2:
        if (VbrControl_init_2pass_vbr_encoding(passtmpfile,
		    lavc_venc_context.bit_rate,
		    (float)mux_v->h.dwRate/mux_v->h.dwScale,
		    100, /* crispness */
		    5) == -1){
	    mp_msg(MSGT_MENCODER,MSGL_ERR,"2pass failed: filename=%s\n", passtmpfile);
	    pass=0;
	} else
	    lavc_venc_context.flags|=CODEC_FLAG_QSCALE|CODEC_FLAG_TYPE; // VBR
	break;
    }

    if (avcodec_open(&lavc_venc_context, vf->priv->codec) != 0) {
	mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantOpenCodec);
	return 0;
    }

    if (lavc_venc_context.codec->encode == NULL) {
	mp_msg(MSGT_MENCODER,MSGL_ERR,"avcodec init failed (ctx->codec->encode == NULL)!\n");
	return 0;
    }

    return 1;
}

static int control(struct vf_instance_s* vf, int request, void* data){

    return CONTROL_UNKNOWN;
}

static int query_format(struct vf_instance_s* vf, unsigned int fmt){
    switch(fmt){
    case IMGFMT_YV12:
    case IMGFMT_IYUV:
    case IMGFMT_I420:
	return VFCAP_CSP_SUPPORTED | VFCAP_ACCEPT_STRIDE;
    }
    return 0;
}

static void put_image(struct vf_instance_s* vf, mp_image_t *mpi){
    int out_size;
    AVPicture lavc_venc_picture;

    lavc_venc_picture.data[0]=mpi->planes[0];
    lavc_venc_picture.data[1]=mpi->planes[1];
    lavc_venc_picture.data[2]=mpi->planes[2];
    lavc_venc_picture.linesize[0]=mpi->stride[0];
    lavc_venc_picture.linesize[1]=mpi->stride[1];
    lavc_venc_picture.linesize[2]=mpi->stride[2];

    if(pass==2){ // handle 2-pass:
	lavc_venc_context.flags|=CODEC_FLAG_QSCALE; // enable VBR
	lavc_venc_context.quality=VbrControl_get_quant();
	lavc_venc_context.key_frame=VbrControl_get_intra();
	lavc_venc_context.gop_size=0x3fffffff;
	out_size = avcodec_encode_video(&lavc_venc_context, mux_v->buffer, mux_v->buffer_size,
	    &lavc_venc_picture);
	VbrControl_update_2pass_vbr_encoding(lavc_venc_context.mv_bits,
	      lavc_venc_context.i_tex_bits+lavc_venc_context.p_tex_bits,
	      8*out_size);
    } else {
	out_size = avcodec_encode_video(&lavc_venc_context, mux_v->buffer, mux_v->buffer_size,
	    &lavc_venc_picture);

	if(pass==1){
	  VbrControl_update_2pass_vbr_analysis(lavc_venc_context.key_frame,
	      lavc_venc_context.mv_bits,
	      lavc_venc_context.i_tex_bits+lavc_venc_context.p_tex_bits,
	      8*out_size, lavc_venc_context.quality);
	}
	
    }

    mencoder_write_chunk(mux_v,out_size,lavc_venc_context.key_frame?0x10:0);
}

static void uninit(struct vf_instance_s* vf){
    avcodec_close(&lavc_venc_context);
}

//===========================================================================//

static int vf_open(vf_instance_t *vf, char* args){
    vf->uninit=uninit;
    vf->config=config;
    vf->control=control;
    vf->query_format=query_format;
    vf->put_image=put_image;
    vf->priv=malloc(sizeof(struct vf_priv_s));
    memset(vf->priv,0,sizeof(struct vf_priv_s));
    vf->priv->mux=args;

    /* XXX: hack: some of the MJPEG decoder DLL's needs exported huffman
       table, so we define a zero-table, also lavc mjpeg encoder is putting
       huffman tables into the stream, so no problem */
    if (lavc_param_vcodec && !strcasecmp(lavc_param_vcodec, "mjpeg"))
    {
	mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)+28);
	memset(mux_v->bih, 0, sizeof(BITMAPINFOHEADER)+28);
	mux_v->bih->biSize=sizeof(BITMAPINFOHEADER)+28;
    }
    else
    {
	mux_v->bih=malloc(sizeof(BITMAPINFOHEADER));
	memset(mux_v->bih, 0, sizeof(BITMAPINFOHEADER));
	mux_v->bih->biSize=sizeof(BITMAPINFOHEADER);
    }
    mux_v->bih->biWidth=0;
    mux_v->bih->biHeight=0;
    mux_v->bih->biPlanes=1;
    mux_v->bih->biBitCount=24;
    if (!lavc_param_vcodec)
    {
	printf("No libavcodec codec specified! It's required!\n");
	return 0;
    }

    if (!strcasecmp(lavc_param_vcodec, "mpeg1") || !strcasecmp(lavc_param_vcodec, "mpeg1video"))
	mux_v->bih->biCompression = mmioFOURCC('m', 'p', 'g', '1');
    else if (!strcasecmp(lavc_param_vcodec, "h263") || !strcasecmp(lavc_param_vcodec, "h263p"))
	mux_v->bih->biCompression = mmioFOURCC('h', '2', '6', '3');
    else if (!strcasecmp(lavc_param_vcodec, "rv10"))
	mux_v->bih->biCompression = mmioFOURCC('R', 'V', '1', '0');
    else if (!strcasecmp(lavc_param_vcodec, "mjpeg"))
	mux_v->bih->biCompression = mmioFOURCC('M', 'J', 'P', 'G');
    else if (!strcasecmp(lavc_param_vcodec, "mpeg4"))
	mux_v->bih->biCompression = mmioFOURCC('D', 'I', 'V', 'X');
    else if (!strcasecmp(lavc_param_vcodec, "msmpeg4"))
	mux_v->bih->biCompression = mmioFOURCC('d', 'i', 'v', '3');
    else if (!strcasecmp(lavc_param_vcodec, "msmpeg4v2"))
	mux_v->bih->biCompression = mmioFOURCC('M', 'P', '4', '2');
    else
	mux_v->bih->biCompression = mmioFOURCC(lavc_param_vcodec[0],
		lavc_param_vcodec[1], lavc_param_vcodec[2], lavc_param_vcodec[3]); /* FIXME!!! */

    if (!avcodec_inited){
	avcodec_init();
	avcodec_register_all();
	avcodec_inited=1;
    }

    vf->priv->codec = (AVCodec *)avcodec_find_encoder_by_name(lavc_param_vcodec);
    if (!vf->priv->codec) {
	mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_MissingLAVCcodec, lavc_param_vcodec);
	return 0;
    }

    return 1;
}

vf_info_t ve_info_lavc = {
    "libavcodec encoder",
    "lavc",
    "A'rpi and Alex",
    "for internal use by mencoder",
    vf_open
};

//===========================================================================//
#endif