1 /* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.fr/>.
5 It may be used under the terms of the GNU General Public License. */
10 struct hb_work_private_s
13 AVCodecContext * context;
17 int encavcodecInit( hb_work_object_t *, hb_job_t * );
18 int encavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
19 void encavcodecClose( hb_work_object_t * );
21 hb_work_object_t hb_encavcodec =
24 "MPEG-4 encoder (libavcodec)",
30 int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
33 AVCodecContext * context;
34 int rate_num, rate_den;
36 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
41 codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
44 hb_log( "hb_work_encavcodec_init: avcodec_find_encoder "
47 context = avcodec_alloc_context();
48 if( job->vquality < 0.0 )
51 context->bit_rate = 1000 * job->vbitrate;
52 context->bit_rate_tolerance = 10 * context->bit_rate;
56 /* Constant quantizer */
57 // These settings produce better image quality than
58 // what was previously used
59 context->flags |= CODEC_FLAG_QSCALE;
60 if (job->vquality < 1.0)
63 vquality = 31 - job->vquality * 31;
64 // A value of 0 has undefined behavior
65 // and ffmpeg qp has integral increments
68 context->global_quality = FF_QP2LAMBDA * vquality + 0.5;
72 context->global_quality = FF_QP2LAMBDA * job->vquality + 0.5;
74 context->mb_decision = 1;
75 hb_log( "encavcodec: encoding at constant quantizer %d",
76 context->global_quality );
78 context->width = job->width;
79 context->height = job->height;
80 rate_num = job->vrate_base;
81 rate_den = job->vrate;
82 if (rate_den == 27000000)
85 for (ii = 0; ii < hb_video_rates_count; ii++)
87 if (abs(rate_num - hb_video_rates[ii].rate) < 10)
89 rate_num = hb_video_rates[ii].rate;
94 hb_reduce(&rate_num, &rate_den, rate_num, rate_den);
95 if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
97 hb_log( "encavcodec: truncating framerate %d / %d",
100 while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
105 context->time_base = (AVRational) { rate_num, rate_den };
106 context->gop_size = 10 * job->vrate / job->vrate_base;
107 context->pix_fmt = PIX_FMT_YUV420P;
109 if( job->anamorphic.mode )
111 context->sample_aspect_ratio.num = job->anamorphic.par_width;
112 context->sample_aspect_ratio.den = job->anamorphic.par_height;
114 hb_log( "encavcodec: encoding with stored aspect %d/%d",
115 job->anamorphic.par_width, job->anamorphic.par_height );
118 if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) )
120 context->flags |= CODEC_FLAG_GLOBAL_HEADER;
122 if( job->mux & HB_MUX_PSP )
124 context->flags |= CODEC_FLAG_BITEXACT;
128 context->flags |= CODEC_FLAG_GRAY;
131 if( job->pass != 0 && job->pass != -1 )
133 char filename[1024]; memset( filename, 0, 1024 );
134 hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
138 pv->file = fopen( filename, "wb" );
139 context->flags |= CODEC_FLAG_PASS1;
146 pv->file = fopen( filename, "rb" );
147 fseek( pv->file, 0, SEEK_END );
148 size = ftell( pv->file );
149 fseek( pv->file, 0, SEEK_SET );
150 log = malloc( size + 1 );
152 fread( log, size, 1, pv->file );
156 context->flags |= CODEC_FLAG_PASS2;
157 context->stats_in = log;
161 if( hb_avcodec_open( context, codec ) )
163 hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
165 pv->context = context;
167 if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 )
171 w->config->mpeg4.length = 15;
172 memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 );
174 w->config->mpeg4.length = context->extradata_size;
175 memcpy( w->config->mpeg4.bytes, context->extradata,
176 context->extradata_size );
183 /***********************************************************************
185 ***********************************************************************
187 **********************************************************************/
188 void encavcodecClose( hb_work_object_t * w )
190 hb_work_private_t * pv = w->private_data;
194 hb_deep_log( 2, "encavcodec: closing libavcodec" );
195 avcodec_flush_buffers( pv->context );
196 hb_avcodec_close( pv->context );
203 w->private_data = NULL;
206 /***********************************************************************
208 ***********************************************************************
210 **********************************************************************/
211 int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
212 hb_buffer_t ** buf_out )
214 hb_work_private_t * pv = w->private_data;
215 hb_job_t * job = pv->job;
217 hb_buffer_t * in = *buf_in, * buf;
221 /* EOF on input - send it downstream & say we're done */
227 frame = avcodec_alloc_frame();
228 frame->data[0] = in->data;
229 frame->data[1] = frame->data[0] + job->width * job->height;
230 frame->data[2] = frame->data[1] + job->width * job->height / 4;
231 frame->linesize[0] = job->width;
232 frame->linesize[1] = job->width / 2;
233 frame->linesize[2] = job->width / 2;
234 // For constant quality, setting the quality in AVCodecContext
235 // doesn't do the trick. It must be set in the AVFrame.
236 frame->quality = pv->context->global_quality;
238 /* Should be way too large */
239 buf = hb_video_buffer_init( job->width, job->height );
240 buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
242 buf->start = in->start;
243 buf->stop = in->stop;
244 buf->frametype = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF;
251 fprintf( pv->file, "%s", pv->context->stats_out );