/* $Id: encxvid.c,v 1.10 2005/03/09 23:28:39 titer Exp $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ #include "hb.h" #include "xvid.h" int encxvidInit( hb_work_object_t *, hb_job_t * ); int encxvidWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); void encxvidClose( hb_work_object_t * ); hb_work_object_t hb_encxvid = { WORK_ENCXVID, "MPEG-4 encoder (libxvidcore)", encxvidInit, encxvidWork, encxvidClose }; struct hb_work_private_s { hb_job_t * job; void * xvid; char filename[1024]; int quant; int configDone; }; int encxvidInit( hb_work_object_t * w, hb_job_t * job ) { xvid_gbl_init_t xvid_gbl_init; xvid_enc_create_t create; xvid_plugin_single_t single; xvid_plugin_2pass1_t rc2pass1; xvid_plugin_2pass2_t rc2pass2; xvid_enc_plugin_t plugins[1]; hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; pv->job = job; memset( pv->filename, 0, 1024 ); hb_get_tempory_filename( job->h, pv->filename, "xvid.log" ); memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) ); xvid_gbl_init.version = XVID_VERSION; xvid_global( NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL ); memset( &create, 0, sizeof( create ) ); create.version = XVID_VERSION; create.width = job->width; create.height = job->height; create.zones = NULL; create.num_zones = 0; switch( job->pass ) { case 0: memset( &single, 0, sizeof( single ) ); single.version = XVID_VERSION; if( job->vquality < 0.0 || job->vquality > 1.0 ) { /* Rate control */ single.bitrate = 1000 * job->vbitrate; pv->quant = 0; } else { /* Constant quantizer */ pv->quant = 31 - job->vquality * 30; hb_log( "encxvid: encoding at constant quantizer %d", pv->quant ); } plugins[0].func = xvid_plugin_single; plugins[0].param = &single; break; case 1: memset( &rc2pass1, 0, sizeof( rc2pass1 ) ); rc2pass1.version = XVID_VERSION; rc2pass1.filename = pv->filename; plugins[0].func = xvid_plugin_2pass1; plugins[0].param = &rc2pass1; break; case 2: memset( &rc2pass2, 0, sizeof( rc2pass2 ) ); rc2pass2.version = XVID_VERSION; rc2pass2.filename = pv->filename; rc2pass2.bitrate = 1000 * job->vbitrate; plugins[0].func = xvid_plugin_2pass2; plugins[0].param = &rc2pass2; break; } create.plugins = plugins; create.num_plugins = 1; create.num_threads = 0; create.fincr = job->vrate_base; create.fbase = job->vrate; create.max_key_interval = 10 * job->vrate / job->vrate_base; create.max_bframes = 0; create.bquant_ratio = 150; create.bquant_offset = 100; create.frame_drop_ratio = 0; create.global = 0; xvid_encore( NULL, XVID_ENC_CREATE, &create, NULL ); pv->xvid = create.handle; return 0; } /*********************************************************************** * Close *********************************************************************** * **********************************************************************/ void encxvidClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; if( pv->xvid ) { hb_deep_log( 2, "encxvid: closing libxvidcore" ); xvid_encore( pv->xvid, XVID_ENC_DESTROY, NULL, NULL); } free( pv ); w->private_data = NULL; } /*********************************************************************** * Work *********************************************************************** * **********************************************************************/ int encxvidWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_t ** buf_out ) { hb_work_private_t * pv = w->private_data; hb_job_t * job = pv->job; xvid_enc_frame_t frame; hb_buffer_t * in = *buf_in, * buf; if ( in->size <= 0 ) { /* EOF on input - send it downstream & say we're done */ *buf_out = in; *buf_in = NULL; return HB_WORK_DONE; } /* Should be way too large */ buf = hb_video_buffer_init( job->width, job->height ); buf->start = in->start; buf->stop = in->stop; memset( &frame, 0, sizeof( frame ) ); frame.version = XVID_VERSION; frame.bitstream = buf->data; frame.length = -1; frame.input.plane[0] = in->data; frame.input.csp = XVID_CSP_I420; frame.input.stride[0] = job->width; frame.vol_flags = 0; frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED; if( job->anamorphic.mode ) { frame.par = XVID_PAR_EXT; frame.par_width = job->anamorphic.par_width; frame.par_height = job->anamorphic.par_height; } if( job->grayscale ) { frame.vop_flags |= XVID_VOP_GREYSCALE; } frame.type = XVID_TYPE_AUTO; frame.quant = pv->quant; frame.motion = 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; frame.quant_intra_matrix = NULL; frame.quant_inter_matrix = NULL; buf->size = xvid_encore( pv->xvid, XVID_ENC_ENCODE, &frame, NULL ); buf->frametype = ( frame.out_flags & XVID_KEYFRAME ) ? HB_FRAME_KEY : HB_FRAME_REF; if( !pv->configDone ) { int vol_start, vop_start; for( vol_start = 0; ; vol_start++ ) { if( buf->data[vol_start] == 0x0 && buf->data[vol_start+1] == 0x0 && buf->data[vol_start+2] == 0x1 && buf->data[vol_start+3] == 0x20 ) { break; } } for( vop_start = vol_start + 4; ; vop_start++ ) { if( buf->data[vop_start] == 0x0 && buf->data[vop_start+1] == 0x0 && buf->data[vop_start+2] == 0x1 && buf->data[vop_start+3] == 0xB6 ) { break; } } hb_deep_log( 2, "encxvid: VOL size is %d bytes", vop_start - vol_start ); job->config.mpeg4.length = vop_start - vol_start; memcpy( job->config.mpeg4.bytes, &buf->data[vol_start], job->config.mpeg4.length ); pv->configDone = 1; } *buf_out = buf; return HB_WORK_OK; }