X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;ds=sidebyside;f=libhb%2Fencavcodec.c;h=22eb286d524158c8e300c04d8f5143f623e7bfaa;hb=033e32de9c380f54c7d1362a3979da205ebc3a29;hp=deff7c527cdbba2140633b6377d4f5a1be0b74ee;hpb=cdba71d1dca214142fdcca4c52f7672252752c2e;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index deff7c52..22eb286d 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -1,45 +1,42 @@ /* $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 "hbffmpeg.h" -#include "ffmpeg/avcodec.h" - -struct hb_work_object_s +struct hb_work_private_s { - HB_WORK_COMMON; - hb_job_t * job; AVCodecContext * context; FILE * file; }; -/*********************************************************************** - * Local prototypes - **********************************************************************/ -static void Close( hb_work_object_t ** _w ); -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ); +int encavcodecInit( hb_work_object_t *, hb_job_t * ); +int encavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +void encavcodecClose( hb_work_object_t * ); -/*********************************************************************** - * hb_work_encavcodec_init - *********************************************************************** - * - **********************************************************************/ -hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job ) +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; - - hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); - w->name = strdup( "MPEG-4 encoder (libavcodec)" ); - w->work = Work; - w->close = Close; + int rate_num, rate_den; + + hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); + w->private_data = pv; - w->job = job; + pv->job = job; codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); if( !codec ) @@ -48,7 +45,7 @@ hb_work_object_t * hb_work_encavcodec_init( 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; @@ -57,34 +54,88 @@ hb_work_object_t * hb_work_encavcodec_init( 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->mux & HB_MUX_MP4 ) + 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; } + if( job->mux & HB_MUX_PSP ) + { + context->flags |= CODEC_FLAG_BITEXACT; + } if( job->grayscale ) { 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" ); if( job->pass == 1 ) { - w->file = fopen( filename, "wb" ); + pv->file = fopen( filename, "wb" ); context->flags |= CODEC_FLAG_PASS1; } else @@ -92,38 +143,41 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job ) int size; char * log; - w->file = fopen( filename, "rb" ); - fseek( w->file, 0, SEEK_END ); - size = ftell( w->file ); - fseek( w->file, 0, SEEK_SET ); + pv->file = fopen( filename, "rb" ); + fseek( pv->file, 0, SEEK_END ); + size = ftell( pv->file ); + fseek( pv->file, 0, SEEK_SET ); log = malloc( size + 1 ); log[size] = '\0'; - fread( log, size, 1, w->file ); - fclose( w->file ); - w->file = NULL; + fread( log, size, 1, pv->file ); + fclose( pv->file ); + pv->file = NULL; context->flags |= CODEC_FLAG_PASS2; context->stats_in = log; } } - if( avcodec_open( context, codec ) ) + if( hb_avcodec_open( context, codec ) ) { hb_log( "hb_work_encavcodec_init: avcodec_open failed" ); } - w->context = context; + pv->context = context; - if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 ) + if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 ) { -#define c job->config.mpeg4 +#if 0 /* Hem hem */ - c.config = malloc( 15 ); - c.config_length = 15; - memcpy( c.config, context->extradata + 15, 15 ); -#undef c + w->config->mpeg4.length = 15; + memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 ); +#else + w->config->mpeg4.length = context->extradata_size; + memcpy( w->config->mpeg4.bytes, context->extradata, + context->extradata_size ); +#endif } - - return w; + + return 0; } /*********************************************************************** @@ -131,30 +185,22 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job ) *********************************************************************** * **********************************************************************/ -static void Close( hb_work_object_t ** _w ) +void encavcodecClose( hb_work_object_t * w ) { - hb_work_object_t * w = *_w; - hb_job_t * job = w->job; + hb_work_private_t * pv = w->private_data; - if( w->context ) - { - hb_log( "encavcodec: closing libavcodec" ); - avcodec_close( w->context ); - } - if( w->file ) + if( pv->context ) { - fclose( w->file ); + hb_deep_log( 2, "encavcodec: closing libavcodec" ); + avcodec_flush_buffers( pv->context ); + hb_avcodec_close( pv->context ); } - if( job->es_config ) + if( pv->file ) { - free( job->es_config ); - job->es_config = NULL; - job->es_config_length = 0; + fclose( pv->file ); } - - free( w->name ); - free( w ); - *_w = NULL; + free( pv ); + w->private_data = NULL; } /*********************************************************************** @@ -162,13 +208,22 @@ static void Close( hb_work_object_t ** _w ) *********************************************************************** * **********************************************************************/ -static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, - hb_buffer_t ** buf_out ) +int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) { - hb_job_t * job = w->job; + hb_work_private_t * pv = w->private_data; + hb_job_t * job = pv->job; 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; @@ -176,21 +231,24 @@ static int Work( 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->size = avcodec_encode_video( w->context, buf->data, buf->alloc, + 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 = w->context->coded_frame->key_frame; + buf->frametype = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF; av_free( frame ); if( job->pass == 1 ) { /* Write stats */ - fprintf( w->file, "%s", w->context->stats_out ); + fprintf( pv->file, "%s", pv->context->stats_out ); } *buf_out = buf;