/* $Id: encx264.c,v 1.21 2005/11/04 13:09:41 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
#include "hb.h"
#include "x264.h"
int encx264Init( hb_work_object_t *, hb_job_t * );
int encx264Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
void encx264Close( hb_work_object_t * );
hb_work_object_t hb_encx264 =
{
WORK_ENCX264,
"H.264/AVC encoder (libx264)",
encx264Init,
encx264Work,
encx264Close
};
struct hb_work_private_s
{
hb_job_t * job;
x264_t * x264;
x264_picture_t pic_in;
x264_picture_t pic_out;
char filename[1024];
};
/***********************************************************************
* hb_work_encx264_init
***********************************************************************
*
**********************************************************************/
int encx264Init( hb_work_object_t * w, hb_job_t * job )
{
x264_param_t param;
x264_nal_t * nal;
int nal_count;
int i, size;
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, "x264.log" );
x264_param_default( ¶m );
param.i_threads = hb_get_cpu_count();
param.i_width = job->width;
param.i_height = job->height;
param.i_fps_num = job->vrate;
param.i_fps_den = job->vrate_base;
param.i_keyint_max = 20 * job->vrate / job->vrate_base;
param.i_log_level = X264_LOG_NONE;
if( job->h264_level )
{
param.i_threads = 1;
param.b_cabac = 0;
param.i_level_idc = job->h264_level;
hb_log( "encx264: encoding at level %i",
param.i_level_idc );
}
/* Slightly faster with minimal quality lost */
param.analyse.i_subpel_refine = 4;
if( job->vquality >= 0.0 && job->vquality <= 1.0 )
{
/* Constant QP */
param.rc.i_qp_constant = 51 - job->vquality * 51;
hb_log( "encx264: encoding at constant QP %d",
param.rc.i_qp_constant );
}
else
{
/* Rate control */
/* no longer in x264 - see rc.i_rc_method in x264.h */
/* param.rc.b_cbr = 1; */
/* these were the only settings I could use to get accurate ending video bitrate */
param.rc.i_rc_method = X264_RC_CRF;
param.rc.i_vbv_max_bitrate = job->vbitrate;
param.rc.i_vbv_buffer_size = 224;
param.rc.i_rf_constant = 1;
param.rc.i_bitrate = job->vbitrate;
switch( job->pass )
{
case 1:
param.rc.i_rc_method = X264_RC_ABR;
param.rc.b_stat_write = 1;
param.rc.psz_stat_out = pv->filename;
break;
case 2:
param.rc.i_rc_method = X264_RC_ABR;
param.rc.b_stat_read = 1;
param.rc.psz_stat_in = pv->filename;
break;
}
}
hb_log( "encx264: opening libx264 (pass %d)", job->pass );
pv->x264 = x264_encoder_open( ¶m );
w->config->mpeg4.length = 0;
x264_encoder_headers( pv->x264, &nal, &nal_count );
for( i = 0; i < nal_count; i++ )
{
size = sizeof( w->config->mpeg4.bytes ) - w->config->mpeg4.length;
x264_nal_encode( &w->config->mpeg4.bytes[w->config->mpeg4.length],
&size, 1, &nal[i] );
w->config->mpeg4.length += size;
}
x264_picture_alloc( &pv->pic_in, X264_CSP_I420,
job->width, job->height );
return 0;
}
void encx264Close( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
x264_encoder_close( pv->x264 );
/* TODO */
}
int encx264Work( 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;
hb_buffer_t * in = *buf_in, * buf;
int i_nal;
x264_nal_t * nal;
int i;
/* XXX avoid this memcpy ? */
memcpy( pv->pic_in.img.plane[0], in->data, job->width * job->height );
if( job->grayscale )
{
/* XXX x264 has currently no option for grayscale encoding */
memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );
memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 );
}
else
{
memcpy( pv->pic_in.img.plane[1], in->data + job->width * job->height,
job->width * job->height / 4 );
memcpy( pv->pic_in.img.plane[2], in->data + 5 * job->width *
job->height / 4, job->width * job->height / 4 );
}
pv->pic_in.i_type = X264_TYPE_AUTO;
pv->pic_in.i_qpplus1 = 0;
x264_encoder_encode( pv->x264, &nal, &i_nal,
&pv->pic_in, &pv->pic_out );
/* Should be way too large */
buf = hb_buffer_init( 3 * job->width * job->height / 2 );
buf->start = in->start;
buf->stop = in->stop;
buf->key = ( pv->pic_out.i_type == X264_TYPE_IDR );
buf->size = 0;
for( i = 0; i < i_nal; i++ )
{
int size, data;
data = buf->alloc - buf->size;
if( ( size = x264_nal_encode( &buf->data[buf->size], &data,
1, &nal[i] ) ) > 0 )
{
buf->size += size;
}
}
*buf_out = buf;
return HB_WORK_OK;
}