diff options
author | jstebbins <[email protected]> | 2011-03-19 20:58:01 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2011-03-19 20:58:01 +0000 |
commit | 24d2785ae92568533caed9528944167ca27e8905 (patch) | |
tree | 6449a94ad4a22c66bfaddc8df9bce45080ceceb8 /libhb/encavcodec.c | |
parent | de22836e9e399616ea04051eabd8b8cbedb4e8cb (diff) |
Add mpeg-2 encoding support to libhb, cli, and lingui
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3853 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/encavcodec.c')
-rw-r--r-- | libhb/encavcodec.c | 99 |
1 files changed, 69 insertions, 30 deletions
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index e70d9279b..b2cebee64 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -47,7 +47,7 @@ void encavcodecClose( hb_work_object_t * ); hb_work_object_t hb_encavcodec = { WORK_ENCAVCODEC, - "MPEG-4 encoder (libavcodec)", + "FFMPEG encoder (libavcodec)", encavcodecInit, encavcodecWork, encavcodecClose @@ -57,17 +57,34 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) { AVCodec * codec; AVCodecContext * context; - int rate_num, rate_den; + AVRational fps; hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; pv->job = job; - codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); + switch ( w->codec_param ) + { + case CODEC_ID_MPEG4: + { + hb_log("encavcodecInit: MPEG-4 ASP encoder"); + } break; + case CODEC_ID_MPEG2VIDEO: + { + hb_log("encavcodecInit: MPEG-2 encoder"); + } break; + default: + { + hb_error("encavcodecInit: unsupported encoder!"); + return 1; + } + } + + codec = avcodec_find_encoder( w->codec_param ); if( !codec ) { - hb_log( "hb_work_encavcodec_init: avcodec_find_encoder " + hb_log( "encavcodecInit: avcodec_find_encoder " "failed" ); } context = avcodec_alloc_context3( codec ); @@ -79,45 +96,64 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) if( job->pass == 2 ) { hb_interjob_t * interjob = hb_interjob_get( job->h ); - rate_num = interjob->vrate_base; - rate_den = interjob->vrate; + fps.den = interjob->vrate_base; + fps.num = interjob->vrate; } else { - rate_num = job->vrate_base; - rate_den = job->vrate; + fps.den = job->vrate_base; + fps.num = job->vrate; } - // If the rate_den is 27000000, there's a good chance this is + // If the fps.num is 27000000, there's a good chance this is // a standard rate that we have in our hb_video_rates table. // Because of rounding errors and approximations made while // measuring framerate, the actual value may not be exact. So // we look for rates that are "close" and make an adjustment - // to rate_num. - if (rate_den == 27000000) + // to fps.den. + if (fps.num == 27000000) { int ii; for (ii = 0; ii < hb_video_rates_count; ii++) { - if (abs(rate_num - hb_video_rates[ii].rate) < 10) + if (abs(fps.den - hb_video_rates[ii].rate) < 10) { - rate_num = hb_video_rates[ii].rate; + fps.den = hb_video_rates[ii].rate; break; } } } - hb_reduce(&rate_num, &rate_den, rate_num, rate_den); - if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF)) + hb_reduce(&fps.den, &fps.num, fps.den, fps.num); + + // Check that the framerate is supported. If not, pick the closest. + // The mpeg2 codec only supports a specific list of frame rates. + if (codec->supported_framerates) { - hb_log( "encavcodec: truncating framerate %d / %d", - rate_num, rate_den ); + AVRational supported_fps; + supported_fps = codec->supported_framerates[av_find_nearest_q_idx(fps, codec->supported_framerates)]; + if (supported_fps.num != fps.num || supported_fps.den != fps.den) + { + hb_log( "encavcodec: framerate %d / %d is not supported. Using %d / %d.", + fps.num, fps.den, supported_fps.num, supported_fps.den ); + fps = supported_fps; + } } - while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF)) + else if ((fps.num & ~0xFFFF) || (fps.den & ~0xFFFF)) { - rate_num >>= 1; - rate_den >>= 1; + // This may only be required for mpeg4 video. But since + // our only supported options are mpeg2 and mpeg4, there is + // no need to check codec type. + hb_log( "encavcodec: truncating framerate %d / %d", + fps.num, fps.den ); + while ((fps.num & ~0xFFFF) || (fps.den & ~0xFFFF)) + { + fps.num >>= 1; + fps.den >>= 1; + } } - context->time_base = (AVRational) { rate_num, rate_den }; + + context->time_base.den = fps.num; + context->time_base.num = fps.den; context->gop_size = 10 * (int)( (double)job->vrate / (double)job->vrate_base + 0.5 ); /* @@ -178,7 +214,9 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) { /* Rate control */ context->bit_rate = 1000 * job->vbitrate; - context->bit_rate_tolerance = 10 * context->bit_rate; + // ffmpeg's mpeg2 encoder requires that the bit_rate_tolerance be >= + // bitrate * fps + context->bit_rate_tolerance = context->bit_rate * av_q2d(fps) + 1; } else { @@ -257,10 +295,11 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) if( hb_avcodec_open( context, codec ) ) { - hb_log( "hb_work_encavcodec_init: avcodec_open failed" ); + hb_log( "encavcodecInit: avcodec_open failed" ); } pv->context = context; + job->areBframes = 0; if ( context->has_b_frames ) { job->areBframes = 1; @@ -284,7 +323,7 @@ void encavcodecClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; - if( pv->context ) + if( pv->context && pv->context->codec ) { hb_deep_log( 2, "encavcodec: closing libavcodec" ); avcodec_flush_buffers( pv->context ); @@ -506,6 +545,12 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } buf = process_delay_list( pv, buf ); } + + if( job->pass == 1 ) + { + /* Write stats */ + fprintf( pv->file, "%s", pv->context->stats_out ); + } } else { @@ -516,12 +561,6 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, av_free( frame ); - if( job->pass == 1 ) - { - /* Write stats */ - fprintf( pv->file, "%s", pv->context->stats_out ); - } - *buf_out = buf; return HB_WORK_OK; |