X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fencavcodec.c;h=22eb286d524158c8e300c04d8f5143f623e7bfaa;hb=47efd7ba710d51cac8eb6f2b04ae468fea07d27d;hp=f0460690698d022ef352f023ba0faa012279efc7;hpb=4c8043dc840793d01efa2edb1668c54a520c2e9a;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index f0460690..22eb286d 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -1,12 +1,11 @@ /* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 titer Exp $ This file is part of the HandBrake source code. - Homepage: . + Homepage: . It may be used under the terms of the GNU General Public License. */ #include "hb.h" - -#include "ffmpeg/avcodec.h" +#include "hbffmpeg.h" struct hb_work_private_s { @@ -20,19 +19,20 @@ int encavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); void encavcodecClose( hb_work_object_t * ); hb_work_object_t hb_encavcodec = -{ +{ WORK_ENCAVCODEC, "MPEG-4 encoder (libavcodec)", encavcodecInit, encavcodecWork, encavcodecClose -}; +}; int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) { AVCodec * codec; AVCodecContext * context; - + int rate_num, rate_den; + hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; @@ -45,7 +45,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) "failed" ); } context = avcodec_alloc_context(); - if( job->vquality < 0.0 || job->vquality > 1.0 ) + if( job->vquality < 0.0 ) { /* Rate control */ context->bit_rate = 1000 * job->vbitrate; @@ -54,17 +54,67 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) else { /* Constant quantizer */ - context->qmin = 31 - job->vquality * 30; - context->qmax = context->qmin; + // These settings produce better image quality than + // what was previously used + context->flags |= CODEC_FLAG_QSCALE; + if (job->vquality < 1.0) + { + float vquality; + vquality = 31 - job->vquality * 31; + // A value of 0 has undefined behavior + // and ffmpeg qp has integral increments + if (vquality < 1.0) + vquality = 1.0; + context->global_quality = FF_QP2LAMBDA * vquality + 0.5; + } + else + { + context->global_quality = FF_QP2LAMBDA * job->vquality + 0.5; + } + context->mb_decision = 1; hb_log( "encavcodec: encoding at constant quantizer %d", - context->qmin ); + context->global_quality ); } context->width = job->width; context->height = job->height; - context->time_base = (AVRational) { job->vrate_base, job->vrate }; + rate_num = job->vrate_base; + rate_den = job->vrate; + if (rate_den == 27000000) + { + int ii; + for (ii = 0; ii < hb_video_rates_count; ii++) + { + if (abs(rate_num - hb_video_rates[ii].rate) < 10) + { + rate_num = hb_video_rates[ii].rate; + break; + } + } + } + hb_reduce(&rate_num, &rate_den, rate_num, rate_den); + if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF)) + { + hb_log( "encavcodec: truncating framerate %d / %d", + rate_num, rate_den ); + } + while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF)) + { + rate_num >>= 1; + rate_den >>= 1; + } + context->time_base = (AVRational) { rate_num, rate_den }; context->gop_size = 10 * job->vrate / job->vrate_base; context->pix_fmt = PIX_FMT_YUV420P; + if( job->anamorphic.mode ) + { + context->sample_aspect_ratio.num = job->anamorphic.par_width; + context->sample_aspect_ratio.den = job->anamorphic.par_height; + + hb_log( "encavcodec: encoding with stored aspect %d/%d", + job->anamorphic.par_width, job->anamorphic.par_height ); + } + if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) { context->flags |= CODEC_FLAG_GLOBAL_HEADER; @@ -78,7 +128,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) context->flags |= CODEC_FLAG_GRAY; } - if( job->pass ) + if( job->pass != 0 && job->pass != -1 ) { char filename[1024]; memset( filename, 0, 1024 ); hb_get_tempory_filename( job->h, filename, "ffmpeg.log" ); @@ -108,7 +158,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) } } - if( avcodec_open( context, codec ) ) + if( hb_avcodec_open( context, codec ) ) { hb_log( "hb_work_encavcodec_init: avcodec_open failed" ); } @@ -126,7 +176,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) context->extradata_size ); #endif } - + return 0; } @@ -141,13 +191,16 @@ void encavcodecClose( hb_work_object_t * w ) if( pv->context ) { - hb_log( "encavcodec: closing libavcodec" ); - avcodec_close( pv->context ); + hb_deep_log( 2, "encavcodec: closing libavcodec" ); + avcodec_flush_buffers( pv->context ); + hb_avcodec_close( pv->context ); } if( pv->file ) { fclose( pv->file ); } + free( pv ); + w->private_data = NULL; } /*********************************************************************** @@ -163,6 +216,14 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, AVFrame * 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; + } + frame = avcodec_alloc_frame(); frame->data[0] = in->data; frame->data[1] = frame->data[0] + job->width * job->height; @@ -170,14 +231,17 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, frame->linesize[0] = job->width; frame->linesize[1] = job->width / 2; frame->linesize[2] = job->width / 2; + // For constant quality, setting the quality in AVCodecContext + // doesn't do the trick. It must be set in the AVFrame. + frame->quality = pv->context->global_quality; /* Should be way too large */ - buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf = hb_video_buffer_init( job->width, job->height ); buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc, frame ); buf->start = in->start; buf->stop = in->stop; - buf->key = pv->context->coded_frame->key_frame; + buf->frametype = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF; av_free( frame );