使用xvid进行编码

来源:互联网 发布:青岛人工智能发展情况 编辑:程序博客网 时间:2024/04/26 06:11

/*****************************************************************************
 *  Application notes :
 *                     
 *  A sequence of raw YUV I420 pics or YUV I420 PGM file format is encoded
 *  The speed is measured and frames' PSNR are taken from core.
 *                    
 *  The program is plain C and needs no libraries except for libxvidcore,
 *  and maths-lib.
 *
 *  Use ./xvid_encraw -help for a list of options
 * 
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>

#include "xvid.h"

#undef READ_PNM

/*****************************************************************************
 *                            Quality presets
 ****************************************************************************/

static const int motion_presets[] = {
 /* quality 0 */
 0,

 /* quality 1 */
 XVID_ME_ADVANCEDDIAMOND16,

 /* quality 2 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16,

 /* quality 3 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8,

 /* quality 4 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

 /* quality 5 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

 /* quality 6 */
 XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 |
 XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 |
 XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP,

};
#define ME_ELEMENTS (sizeof(motion_presets)/sizeof(motion_presets[0]))

static const int vop_presets[] = {
 /* quality 0 */
 0,

 /* quality 1 */
 0,

 /* quality 2 */
 XVID_VOP_HALFPEL,

 /* quality 3 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

 /* quality 4 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V,

 /* quality 5 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
 XVID_VOP_TRELLISQUANT,

 /* quality 6 */
 XVID_VOP_HALFPEL | XVID_VOP_INTER4V |
 XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED,

};
#define VOP_ELEMENTS (sizeof(vop_presets)/sizeof(vop_presets[0]))

/*****************************************************************************
 *                     Command line global variables
 ****************************************************************************/

#define MAX_ZONES   64

static xvid_enc_zone_t ZONES[MAX_ZONES];
static int NUM_ZONES = 0;

/* Maximum number of frames to encode */
#define ABS_MAXFRAMENR 9999

static int ARG_STATS = 0;
static int ARG_DUMP = 0;
static int ARG_LUMIMASKING = 0;
static int ARG_BITRATE = 0;
static int ARG_SINGLE = 1;
static char *ARG_PASS1 = 0;
static char *ARG_PASS2 = 0;
static int ARG_QUALITY = ME_ELEMENTS - 1;
static float ARG_FRAMERATE = 25.00f;
static int ARG_MAXFRAMENR = ABS_MAXFRAMENR;
static int ARG_MAXKEYINTERVAL = 0;
static char *ARG_INPUTFILE = NULL;
static int ARG_INPUTTYPE = 0;
static int ARG_SAVEMPEGSTREAM = 0;
static int ARG_SAVEINDIVIDUAL = 0;
static int XDIM = 352;
static int YDIM = 288;
//static int XDIM = 176;
//static int YDIM = 144;
static int ARG_BQRATIO = 150;
static int ARG_BQOFFSET = 100;
static int ARG_MAXBFRAMES = 0;
static int ARG_PACKED = 0;
static int ARG_DEBUG = 0;
static int ARG_VOPDEBUG = 0;
static int ARG_GREYSCALE = 0;
static int ARG_QTYPE = 0;
static int ARG_QMATRIX = 0;
static int ARG_GMC = 0;
static int ARG_INTERLACING = 0;
static int ARG_QPEL = 0;
static int ARG_TURBO = 0;
static int ARG_VHQMODE = 0;
static int ARG_BVHQ = 0;
static int ARG_CLOSED_GOP = 0;

#define IMAGE_SIZE(x,y) ((x)*(y)*3/2)

#define SMALL_EPS (1e-10)

/****************************************************************************
 *                     Nasty global vars ;-)
 ***************************************************************************/
/* Internal structures (handles) for encoding and decoding */
static void *enc_handle = NULL;

static unsigned char qmatrix_intra[64];
static unsigned char qmatrix_inter[64];

/*****************************************************************************
 *               Local prototypes
 ****************************************************************************/

/* PGM related functions */

/* Encoder related functions */
static int enc_init(int use_assembler);
static int enc_stop();
static int enc_main(unsigned char *image,
     unsigned char *bitstream,
     int *key,
     int *stats_type,
     int *stats_quant,
     int *stats_length,
     int stats[3]);
/*****************************************************************************
 *     Routines for encoding: init encoder, frame step, release encoder
 ****************************************************************************/

#define FRAMERATE_INCR 1001


/* Initialize encoder for first use, pass all needed parameters to the codec */
static int
enc_init(int use_assembler)
{
 int xerr;
 //xvid_plugin_cbr_t cbr;
    xvid_plugin_single_t single;
 xvid_plugin_2pass1_t rc2pass1;
 xvid_plugin_2pass2_t rc2pass2;
 //xvid_plugin_fixed_t rcfixed;
 xvid_enc_plugin_t plugins[7];
 xvid_gbl_init_t xvid_gbl_init;
 xvid_enc_create_t xvid_enc_create;

 /*------------------------------------------------------------------------
  * XviD core initialization
  *----------------------------------------------------------------------*/

 /* Set version -- version checking will done by xvidcore */
 memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init));
 xvid_gbl_init.version = XVID_VERSION;
    xvid_gbl_init.debug = ARG_DEBUG;


 /* Do we have to enable ASM optimizations ? */
 if (use_assembler) {

#ifdef ARCH_IS_IA64
  xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ASM;
#else
  xvid_gbl_init.cpu_flags = 0;
#endif
 } else {
  xvid_gbl_init.cpu_flags = XVID_CPU_FORCE;
 }

 /* Initialize XviD core -- Should be done once per __process__ */
 xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL);

 /*------------------------------------------------------------------------
  * XviD encoder initialization
  *----------------------------------------------------------------------*/

 /* Version again */
 memset(&xvid_enc_create, 0, sizeof(xvid_enc_create));
 xvid_enc_create.version = XVID_VERSION;

 /* Width and Height of input frames */
 xvid_enc_create.width = XDIM;
 xvid_enc_create.height = YDIM;
 xvid_enc_create.profile = XVID_PROFILE_AS_L4;

 /* init plugins  */
    xvid_enc_create.zones = ZONES;
    xvid_enc_create.num_zones = NUM_ZONES;

 xvid_enc_create.plugins = plugins;
 xvid_enc_create.num_plugins = 0;

 if (ARG_SINGLE) {
  memset(&single, 0, sizeof(xvid_plugin_single_t));
  single.version = XVID_VERSION;
  single.bitrate = ARG_BITRATE;

  plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single;
  plugins[xvid_enc_create.num_plugins].param = &single;
  xvid_enc_create.num_plugins++;
 }

 if (ARG_PASS2) {
  memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t));
  rc2pass2.version = XVID_VERSION;
  rc2pass2.filename = ARG_PASS2;
  rc2pass2.bitrate = ARG_BITRATE;

/*  An example of activating VBV could look like this
  rc2pass2.vbv_size     =  3145728;
  rc2pass2.vbv_initial  =  2359296;
  rc2pass2.vbv_maxrate  =  4000000;
  rc2pass2.vbv_peakrate = 10000000;
*/

  plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2;
  plugins[xvid_enc_create.num_plugins].param = &rc2pass2;
  xvid_enc_create.num_plugins++;
 }

 if (ARG_PASS1) {
  memset(&rc2pass1, 0, sizeof(xvid_plugin_2pass1_t));
  rc2pass1.version = XVID_VERSION;
  rc2pass1.filename = ARG_PASS1;

  plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass1;
  plugins[xvid_enc_create.num_plugins].param = &rc2pass1;
  xvid_enc_create.num_plugins++;
 }

 if (ARG_LUMIMASKING) {
  plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking;
  plugins[xvid_enc_create.num_plugins].param = NULL;
  xvid_enc_create.num_plugins++;
 }

 if (ARG_DUMP) {
  plugins[xvid_enc_create.num_plugins].func = xvid_plugin_dump;
  plugins[xvid_enc_create.num_plugins].param = NULL;
  xvid_enc_create.num_plugins++;
 }

#if 0
 if (ARG_DEBUG) {
  plugins[xvid_enc_create.num_plugins].func = rawenc_debug;
  plugins[xvid_enc_create.num_plugins].param = NULL;
  xvid_enc_create.num_plugins++;
 }
#endif

 /* No fancy thread tests */
 xvid_enc_create.num_threads = 0;

 /* Frame rate - Do some quick float fps = fincr/fbase hack */
 if ((ARG_FRAMERATE - (int) ARG_FRAMERATE) < SMALL_EPS) {
  xvid_enc_create.fincr = 1;
  xvid_enc_create.fbase = (int) ARG_FRAMERATE;
 } else {
  xvid_enc_create.fincr = FRAMERATE_INCR;
  xvid_enc_create.fbase = (int) (FRAMERATE_INCR * ARG_FRAMERATE);
 }

 /* Maximum key frame interval */
    if (ARG_MAXKEYINTERVAL > 0) {
        xvid_enc_create.max_key_interval = ARG_MAXKEYINTERVAL;
    }else {
     xvid_enc_create.max_key_interval = (int) ARG_FRAMERATE *10;
    }

 /* Bframes settings */
 xvid_enc_create.max_bframes = ARG_MAXBFRAMES;
 xvid_enc_create.bquant_ratio = ARG_BQRATIO;
 xvid_enc_create.bquant_offset = ARG_BQOFFSET;

 /* Dropping ratio frame -- we don't need that */
 xvid_enc_create.frame_drop_ratio = 0;

 /* Global encoder options */
 xvid_enc_create.global = 0;

 if (ARG_PACKED)
  xvid_enc_create.global |= XVID_GLOBAL_PACKED;

 if (ARG_CLOSED_GOP)
  xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP;

 if (ARG_STATS)
  xvid_enc_create.global |= XVID_GLOBAL_EXTRASTATS_ENABLE;

 /* I use a small value here, since will not encode whole movies, but short clips */
 xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);

 /* Retrieve the encoder instance from the structure */
 enc_handle = xvid_enc_create.handle;

 return (xerr);
}

static int
enc_stop()
{
 int xerr;

 /* Destroy the encoder instance */
 xerr = xvid_encore(enc_handle, XVID_ENC_DESTROY, NULL, NULL);

 return (xerr);
}

static int
enc_main(unsigned char *image,
   unsigned char *bitstream,
   int *key,
   int *stats_type,
   int *stats_quant,
   int *stats_length,
   int sse[3])
{
 int ret;

 xvid_enc_frame_t xvid_enc_frame;
 xvid_enc_stats_t xvid_enc_stats;

 /* Version for the frame and the stats */
 memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame));
 xvid_enc_frame.version = XVID_VERSION;

 memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats));
 xvid_enc_stats.version = XVID_VERSION;

 /* Bind output buffer */
 xvid_enc_frame.bitstream = bitstream;
 xvid_enc_frame.length = -1;

 /* Initialize input image fields */
 if (image) {
  xvid_enc_frame.input.plane[0] = image;
#ifndef READ_PNM
  if (ARG_INPUTTYPE==2)
   xvid_enc_frame.input.csp = XVID_CSP_YV12;
  else
   xvid_enc_frame.input.csp = XVID_CSP_I420;
  xvid_enc_frame.input.stride[0] = XDIM;
#else
  xvid_enc_frame.input.csp = XVID_CSP_BGR;
  xvid_enc_frame.input.stride[0] = XDIM*3;
#endif
 } else {
  xvid_enc_frame.input.csp = XVID_CSP_NULL;
 }

 /* Set up core's general features */
 xvid_enc_frame.vol_flags = 0;
 if (ARG_STATS)
  xvid_enc_frame.vol_flags |= XVID_VOL_EXTRASTATS;
 if (ARG_QTYPE)
  xvid_enc_frame.vol_flags |= XVID_VOL_MPEGQUANT;
 if (ARG_QPEL)
  xvid_enc_frame.vol_flags |= XVID_VOL_QUARTERPEL;
 if (ARG_GMC)
  xvid_enc_frame.vol_flags |= XVID_VOL_GMC;
 if (ARG_INTERLACING)
  xvid_enc_frame.vol_flags |= XVID_VOL_INTERLACING;

 /* Set up core's general features */
 xvid_enc_frame.vop_flags = vop_presets[ARG_QUALITY];

    if (ARG_VOPDEBUG) {
        xvid_enc_frame.vop_flags |= XVID_VOP_DEBUG;
    }

    if (ARG_GREYSCALE) {
        xvid_enc_frame.vop_flags |= XVID_VOP_GREYSCALE;
    }

 /* Frame type -- let core decide for us */
 xvid_enc_frame.type = XVID_TYPE_AUTO;

 /* Force the right quantizer -- It is internally managed by RC plugins */
 xvid_enc_frame.quant = 0;

 /* Set up motion estimation flags */
 xvid_enc_frame.motion = motion_presets[ARG_QUALITY];

 if (ARG_GMC)
  xvid_enc_frame.motion |= XVID_ME_GME_REFINE;

 if (ARG_QPEL)
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16;
 if (ARG_QPEL && (xvid_enc_frame.vop_flags & XVID_VOP_INTER4V))
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8;

 if (ARG_TURBO)
  xvid_enc_frame.motion |= XVID_ME_FASTREFINE16 | XVID_ME_FASTREFINE8 |
         XVID_ME_SKIP_DELTASEARCH | XVID_ME_FAST_MODEINTERPOLATE |
         XVID_ME_BFRAME_EARLYSTOP;

 if (ARG_BVHQ)
  xvid_enc_frame.vop_flags |= XVID_VOP_RD_BVOP;

 switch (ARG_VHQMODE) /* this is the same code as for vfw */
 {
 case 1: /* VHQ_MODE_DECISION */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  break;

 case 2: /* VHQ_LIMITED_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  break;

 case 3: /* VHQ_MEDIUM_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
  break;

 case 4: /* VHQ_WIDE_SEARCH */
  xvid_enc_frame.vop_flags |= XVID_VOP_MODEDECISION_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_HALFPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE16_RD;
  xvid_enc_frame.motion |= XVID_ME_QUARTERPELREFINE8_RD;
  xvid_enc_frame.motion |= XVID_ME_CHECKPREDICTION_RD;
  xvid_enc_frame.motion |= XVID_ME_EXTSEARCH_RD;
  break;

 default :
  break;
 }
   
 if (ARG_QMATRIX) {
  /* We don't use special matrices */
  xvid_enc_frame.quant_intra_matrix = qmatrix_intra;
  xvid_enc_frame.quant_inter_matrix = qmatrix_inter;
 }
 else {
  /* We don't use special matrices */
  xvid_enc_frame.quant_intra_matrix = NULL;
  xvid_enc_frame.quant_inter_matrix = NULL;
 }

 /* Encode the frame */
 ret = xvid_encore(enc_handle, XVID_ENC_ENCODE, &xvid_enc_frame,
       &xvid_enc_stats);

 *key = (xvid_enc_frame.out_flags & XVID_KEYFRAME);
 *stats_type = xvid_enc_stats.type;
 *stats_quant = xvid_enc_stats.quant;
 *stats_length = xvid_enc_stats.length;
 sse[0] = xvid_enc_stats.sse_y;
 sse[1] = xvid_enc_stats.sse_u;
 sse[2] = xvid_enc_stats.sse_v;

 return (ret);
}
#define SRC_FILE "/opt/yuvsource/cif/foreman_cif90.yuv"
//#define SRC_FILE "/opt/yuvsource/qcif/foreman_qcif.yuv"
#define OUT_FILE "cif_tmp.m4d"
#define NUMS 90
typedef struct _m4v_head {
    int magic;
    int size;
}m4v_head;
int main(int argc, char *argv[])
{
    FILE *fp = NULL;
    FILE *fp1 = NULL;
    int fd;
    int i, nbytes;
    char image[XDIM*YDIM*3/2], w_buf[XDIM*YDIM*3/2];
    struct stat tat;

    /*parameters used by xvid*/
    int key;
    int stats_type;
    int stats_quant;
    int stats_length;
    int sse[3];
    int m4v_size;

    memset(w_buf, 0, sizeof(w_buf));


    fp1 = fopen(OUT_FILE, "wb");
    if (NULL == (fp=fopen(SRC_FILE, "rb")))
    {
        printf("fail open file to read/n");
        return -1;
    }
    fd = fileno(fp);
    fstat(fd, &tat);
    if (tat.st_size != sizeof(image)*90)
    {
        printf("not exact file size/n");
        return -1;
    }
    enc_init(0);
    for (i=0; i<NUMS; i++)
    {
        nbytes = fread(image, 1, sizeof(image), fp);
        if (nbytes != sizeof(image))
        {
            printf("fail to read/n");
            return -1;
        }
        m4v_size = enc_main(image,w_buf,&key,&stats_type,&stats_quant,&stats_length,sse);
        //memcpy(w_buf, &head, sizeof(head));
        fwrite(w_buf,1,m4v_size,fp1);
        printf("index[%d] length is %d/n", i, m4v_size);
    }
    fclose(fp);
    fclose(fp1);
    enc_stop();
    return 0;
}