1 /* $Id: encx264.c,v 1.21 2005/11/04 13:09:41 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
13 int encx264Init( hb_work_object_t *, hb_job_t * );
14 int encx264Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
15 void encx264Close( hb_work_object_t * );
17 hb_work_object_t hb_encx264 =
20 "H.264/AVC encoder (libx264)",
26 struct hb_work_private_s
30 x264_picture_t pic_in;
31 x264_picture_t pic_out;
36 /***********************************************************************
37 * hb_work_encx264_init
38 ***********************************************************************
40 **********************************************************************/
41 int encx264Init( hb_work_object_t * w, hb_job_t * job )
47 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
52 memset( pv->filename, 0, 1024 );
53 hb_get_tempory_filename( job->h, pv->filename, "x264.log" );
55 x264_param_default( ¶m );
57 param.i_threads = hb_get_cpu_count();
58 param.i_width = job->width;
59 param.i_height = job->height;
60 param.i_fps_num = job->vrate;
61 param.i_fps_den = job->vrate_base;
62 param.i_keyint_max = 20 * job->vrate / job->vrate_base;
63 param.i_log_level = X264_LOG_INFO;
68 param.i_level_idc = job->h264_level;
69 hb_log( "encx264: encoding at level %i",
73 /* Slightly faster with minimal quality lost */
74 param.analyse.i_subpel_refine = 4;
76 /* This section passes the string x264opts to libx264 for parsing into parameter names and values.
78 The string is set up like this:
79 option1=value1:option2=value 2
81 So, you have to iterate through based on the colons, and then put the left side of the equals sign in "name"
82 and the right side into "value." Then you hand those strings off to x264 for interpretation.
84 This is all based on the universal x264 option handling Loren Merritt implemented in the Mplayer/Mencoder project.
87 char *x264opts = job->x264opts;
88 if(x264opts != NULL && *x264opts != '\0')
92 char *name = x264opts;
96 x264opts += strcspn(x264opts, ":");
103 value = strchr( name, '=' );
111 When B-frames are enabled, the max frame count increments by 1 (regardless of the number of B-frames).
112 If you don't change the duration of the video track when you mux, libmp4 barfs.
113 So, check if the x264opts are using B-frames, and when they are, set the boolean job->areBframes as true.
116 if (!(strcmp(name, "bframes")))
124 /* Here's where the strings are passed to libx264 for parsing. */
125 ret = x264_param_parse(¶m, name, value);
127 /* Let x264 sanity check the options for us*/
128 if(ret == X264_PARAM_BAD_NAME)
129 printf("x264 options: Unknown suboption %s\n", name);
130 if(ret == X264_PARAM_BAD_VALUE)
131 printf("x264 options: Bad argument %s=%s\n", name, value ? value : "(null)");
136 if( job->pixel_ratio )
138 param.vui.i_sar_width = job->pixel_aspect_width;
139 param.vui.i_sar_height = job->pixel_aspect_height;
141 hb_log( "encx264: encoding with stored aspect %d/%d",
142 param.vui.i_sar_width, param.vui.i_sar_height );
146 if( job->vquality >= 0.0 && job->vquality <= 1.0 )
152 param.rc.i_rc_method = X264_RC_CRF;
153 param.rc.f_rf_constant = 51 - job->vquality * 51;
154 hb_log( "encx264: Encoding at constant RF %f",
155 param.rc.f_rf_constant );
160 param.rc.i_rc_method = X264_RC_CQP;
161 param.rc.i_qp_constant = 51 - job->vquality * 51;
162 hb_log( "encx264: encoding at constant QP %d",
163 param.rc.i_qp_constant );
170 param.rc.i_rc_method = X264_RC_ABR;
171 param.rc.i_bitrate = job->vbitrate;
175 param.rc.b_stat_write = 1;
176 param.rc.psz_stat_out = pv->filename;
179 param.rc.b_stat_read = 1;
180 param.rc.psz_stat_in = pv->filename;
185 hb_log( "encx264: opening libx264 (pass %d)", job->pass );
186 pv->x264 = x264_encoder_open( ¶m );
188 x264_encoder_headers( pv->x264, &nal, &nal_count );
190 /* Sequence Parameter Set */
191 w->config->h264.sps_length = 1 + nal[1].i_payload;
192 w->config->h264.sps[0] = 0x67;
193 memcpy( &w->config->h264.sps[1], nal[1].p_payload, nal[1].i_payload );
195 /* Picture Parameter Set */
196 w->config->h264.pps_length = 1 + nal[2].i_payload;
197 w->config->h264.pps[0] = 0x68;
198 memcpy( &w->config->h264.pps[1], nal[2].p_payload, nal[2].i_payload );
200 x264_picture_alloc( &pv->pic_in, X264_CSP_I420,
201 job->width, job->height );
206 void encx264Close( hb_work_object_t * w )
208 hb_work_private_t * pv = w->private_data;
209 x264_encoder_close( pv->x264 );
214 int encx264Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
215 hb_buffer_t ** buf_out )
217 hb_work_private_t * pv = w->private_data;
218 hb_job_t * job = pv->job;
219 hb_buffer_t * in = *buf_in, * buf;
224 /* XXX avoid this memcpy ? */
225 memcpy( pv->pic_in.img.plane[0], in->data, job->width * job->height );
228 /* XXX x264 has currently no option for grayscale encoding */
229 memset( pv->pic_in.img.plane[1], 0x80, job->width * job->height / 4 );
230 memset( pv->pic_in.img.plane[2], 0x80, job->width * job->height / 4 );
234 memcpy( pv->pic_in.img.plane[1], in->data + job->width * job->height,
235 job->width * job->height / 4 );
236 memcpy( pv->pic_in.img.plane[2], in->data + 5 * job->width *
237 job->height / 4, job->width * job->height / 4 );
240 pv->pic_in.i_type = X264_TYPE_AUTO;
241 pv->pic_in.i_qpplus1 = 0;
243 x264_encoder_encode( pv->x264, &nal, &i_nal,
244 &pv->pic_in, &pv->pic_out );
246 /* Should be way too large */
247 buf = hb_buffer_init( 3 * job->width * job->height / 2 );
249 buf->start = in->start;
250 buf->stop = in->stop;
253 for( i = 0; i < i_nal; i++ )
257 data = buf->alloc - buf->size;
258 if( ( size = x264_nal_encode( buf->data + buf->size, &data,
264 if( job->mux & HB_MUX_AVI )
266 if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )
275 switch( buf->data[buf->size+4] & 0x1f )
283 /* H.264 in mp4 (stolen from mp4creator) */
284 buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF;
285 buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF;
286 buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF;
287 buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF;
288 if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST )