/* $Id: XvidEnc.c,v 1.7 2003/11/09 21:26:52 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 "Fifo.h"
#include "Work.h"
#include "XvidEnc.h"
#include "XvidVbr.h"
#include
/* Local prototypes */
static int XvidEncWork( HBWork * );
struct HBXvidEnc
{
HB_WORK_COMMON_MEMBERS
HBHandle * handle;
HBTitle * title;
void * xvid;
vbr_control_t xvidVbr;
XVID_ENC_FRAME frame;
HBBuffer * mpeg4Buffer;
int pass;
};
HBXvidEnc * HBXvidEncInit( HBHandle * handle, HBTitle * title )
{
HBXvidEnc * x;
if( !( x = malloc( sizeof( HBXvidEnc ) ) ) )
{
HBLog( "HBXvidEncInit: malloc() failed, gonna crash" );
return NULL;
}
x->name = strdup( "XvidEnc" );
x->work = XvidEncWork;
x->handle = handle;
x->title = title;
x->xvid = NULL;
x->frame.general = XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V;
x->frame.motion = PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 |
PMV_EXTSEARCH16 | PMV_EARLYSTOP8 |
PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 |
PMV_USESQUARES16;
x->frame.colorspace = XVID_CSP_I420;
x->frame.quant_intra_matrix = NULL;
x->frame.quant_inter_matrix = NULL;
x->mpeg4Buffer = NULL;
x->pass = 42;
return x;
}
void HBXvidEncClose( HBXvidEnc ** _x )
{
HBXvidEnc * x = *_x;
if( x->xvid )
{
HBLog( "HBXvidEnc: closing libxvidcore (pass %d)",
x->pass );
xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL);
vbrFinish( &x->xvidVbr );
}
free( x );
*_x = NULL;
}
static int XvidEncWork( HBWork * w )
{
HBXvidEnc * x = (HBXvidEnc*) w;
HBTitle * title = x->title;
HBBuffer * scaledBuffer;
HBBuffer * mpeg4Buffer;
XVID_ENC_STATS stats;
int didSomething = 0;
if( x->mpeg4Buffer )
{
if( HBFifoPush( title->mpeg4Fifo, &x->mpeg4Buffer ) )
{
didSomething = 1;
}
else
{
return didSomething;
}
}
if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) )
{
didSomething = 1;
}
else
{
return didSomething;
}
/* Init or re-init if needed */
if( scaledBuffer->pass != x->pass )
{
XVID_INIT_PARAM xinit;
XVID_ENC_PARAM xparam;
if( x->xvid )
{
HBLog( "HBXvidEnc: closing libxvidcore (pass %d)",
x->pass );
xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL);
vbrFinish( &x->xvidVbr );
}
x->pass = scaledBuffer->pass;;
HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", x->pass );
xinit.cpu_flags = 0;
xvid_init( NULL, 0, &xinit, NULL );
xparam.width = title->outWidth;
xparam.height = title->outHeight;
xparam.fincr = title->rateBase;
xparam.fbase = title->rate;
xparam.rc_bitrate = title->bitrate * 1024;
/* Default values should be ok */
xparam.rc_reaction_delay_factor = -1;
xparam.rc_averaging_period = -1;
xparam.rc_buffer = -1;
xparam.max_quantizer = -1;
xparam.min_quantizer = -1;
xparam.max_key_interval = -1;
if( xvid_encore( NULL, XVID_ENC_CREATE, &xparam, NULL ) )
{
HBLog( "HBXvidEnc: xvid_encore() failed" );
}
x->xvid = xparam.handle;
/* Init VBR engine */
vbrSetDefaults( &x->xvidVbr );
if( !x->pass )
{
x->xvidVbr.mode = VBR_MODE_1PASS;
}
else if( x->pass == 1 )
{
x->xvidVbr.mode = VBR_MODE_2PASS_1;
}
else
{
x->xvidVbr.mode = VBR_MODE_2PASS_2;
}
x->xvidVbr.fps = (double) title->rate / title->rateBase;
x->xvidVbr.debug = 0;
x->xvidVbr.filename = malloc( 1024 );
memset( x->xvidVbr.filename, 0, 1024 );
snprintf( x->xvidVbr.filename, 1023, "/tmp/HB.%d.xvid.log",
HBGetPid( x->handle ) );
x->xvidVbr.desired_bitrate = title->bitrate * 1024;
x->xvidVbr.max_key_interval = 10 * title->rate / title->rateBase;
vbrInit( &x->xvidVbr );
}
mpeg4Buffer = HBBufferInit( title->outWidth *
title->outHeight * 3 / 2 );
mpeg4Buffer->position = scaledBuffer->position;
x->frame.bitstream = mpeg4Buffer->data;
x->frame.length = -1;
x->frame.image = scaledBuffer->data;
x->frame.quant = vbrGetQuant( &x->xvidVbr );
x->frame.intra = vbrGetIntra( &x->xvidVbr );
x->frame.hint.hintstream = NULL;
if( xvid_encore( x->xvid, XVID_ENC_ENCODE, &x->frame, &stats ) )
{
HBLog( "HBXvidEnc: xvid_encore() failed" );
}
vbrUpdate( &x->xvidVbr, stats.quant, x->frame.intra, stats.hlength,
x->frame.length, stats.kblks, stats.mblks, stats.ublks );
mpeg4Buffer->size = x->frame.length;
mpeg4Buffer->keyFrame = x->frame.intra;
/* Inform the GUI about the current position */
HBPosition( x->handle, scaledBuffer->position );
HBBufferClose( &scaledBuffer );
if( x->pass == 1 )
{
HBBufferClose( &mpeg4Buffer );
return didSomething;
}
x->mpeg4Buffer = mpeg4Buffer;
return didSomething;
}