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 | |
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')
-rw-r--r-- | libhb/common.h | 9 | ||||
-rw-r--r-- | libhb/encavcodec.c | 99 | ||||
-rw-r--r-- | libhb/muxmkv.c | 11 | ||||
-rw-r--r-- | libhb/muxmp4.c | 42 | ||||
-rw-r--r-- | libhb/scan.c | 2 | ||||
-rw-r--r-- | libhb/work.c | 19 |
6 files changed, 136 insertions, 46 deletions
diff --git a/libhb/common.h b/libhb/common.h index fc7b13916..b8045234c 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -223,9 +223,12 @@ struct hb_job_s advanced_opts: string of extra advanced encoder options areBframes: boolean to note if b-frames are included in advanced_opts */ #define HB_VCODEC_MASK 0x0000FF -#define HB_VCODEC_FFMPEG 0x000001 -#define HB_VCODEC_X264 0x000002 -#define HB_VCODEC_THEORA 0x000004 +#define HB_VCODEC_X264 0x000001 +#define HB_VCODEC_THEORA 0x000002 +#define HB_VCODEC_FFMPEG_MPEG4 0x000010 +#define HB_VCODEC_FFMPEG HB_VCODEC_FFMPEG_MPEG4 +#define HB_VCODEC_FFMPEG_MPEG2 0x000020 +#define HB_VCODEC_FFMPEG_MASK 0x0000F0 int vcodec; float vquality; 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; diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index 63f3e94cd..287f677fa 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -103,13 +103,20 @@ static int MKVInit( hb_mux_object_t * m ) if (job->areBframes) track->minCache = 1; break; - case HB_VCODEC_FFMPEG: + case HB_VCODEC_FFMPEG_MPEG4: track->codecID = MK_VCODEC_MP4ASP; track->codecPrivate = job->config.mpeg4.bytes; track->codecPrivateSize = job->config.mpeg4.length; if (job->areBframes) track->minCache = 1; break; + case HB_VCODEC_FFMPEG_MPEG2: + track->codecID = MK_VCODEC_MPEG2; + track->codecPrivate = job->config.mpeg4.bytes; + track->codecPrivateSize = job->config.mpeg4.length; + if (job->areBframes) + track->minCache = 1; + break; case HB_VCODEC_THEORA: { int i; @@ -451,7 +458,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); mk_setFrameFlags(m->file, mux_data->track, timecode, (((job->vcodec == HB_VCODEC_X264 || - job->vcodec == HB_VCODEC_FFMPEG) && + (job->vcodec & HB_VCODEC_FFMPEG_MASK)) && mux_data == job->mux_data) ? (buf->frametype == HB_FRAME_IDR) : ((buf->frametype & HB_FRAME_KEY) != 0)), 0 ); diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index 9387d6499..19a14a0b1 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -154,7 +154,7 @@ static int MP4Init( hb_mux_object_t * m ) MP4AddIPodUUID(m->file, mux_data->track); } } - else /* FFmpeg or XviD */ + else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG4 ) /* FFmpeg MPEG-4 */ { MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 ); mux_data->track = MP4AddVideoTrack( m->file, 90000, @@ -182,6 +182,37 @@ static int MP4Init( hb_mux_object_t * m ) return 0; } } + else if ( job->vcodec == HB_VCODEC_FFMPEG_MPEG2 ) /* FFmpeg MPEG-2 */ + { + mux_data->track = MP4AddVideoTrack( m->file, 90000, + MP4_INVALID_DURATION, job->width, job->height, + MP4_MPEG2_VIDEO_TYPE ); + if (mux_data->track == MP4_INVALID_TRACK_ID) + { + hb_error("muxmp4.c: MP4AddVideoTrack failed!"); + *job->die = 1; + return 0; + } + + /* Tune track chunk duration */ + if( !MP4TuneTrackDurationPerChunk( m, mux_data->track )) + { + return 0; + } + + /* VOL from FFmpeg */ + if (!(MP4SetTrackESConfiguration( m->file, mux_data->track, + job->config.mpeg4.bytes, job->config.mpeg4.length ))) + { + hb_error("muxmp4.c: MP4SetTrackESConfiguration failed!"); + *job->die = 1; + return 0; + } + } + else + { + hb_error("muxmp4.c: Unsupported video encoder!"); + } // COLR atom for color and gamma correction. // Per the notes at: @@ -887,7 +918,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, /* Video */ if( job->vcodec == HB_VCODEC_X264 || - job->vcodec == HB_VCODEC_FFMPEG ) + ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) { if ( buf && buf->start < buf->renderOffset ) { @@ -907,7 +938,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, return 0; if( job->vcodec == HB_VCODEC_X264 || - job->vcodec == HB_VCODEC_FFMPEG ) + ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) { // x264 supplies us with DTS, so offset is PTS - DTS offset = buf->start - buf->renderOffset; @@ -945,7 +976,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } if( job->vcodec == HB_VCODEC_X264 || - job->vcodec == HB_VCODEC_FFMPEG ) + ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) { // x264 supplies us with DTS if ( m->delay_buf ) @@ -1017,7 +1048,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } /* Here's where the sample actually gets muxed. */ - if( ( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_FFMPEG ) + if( ( job->vcodec == HB_VCODEC_X264 || + ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) && mux_data == job->mux_data ) { /* Compute dependency flags. diff --git a/libhb/scan.c b/libhb/scan.c index 901551f55..89fd90b97 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -275,7 +275,7 @@ static void ScanFunc( void * _data ) job->keep_ratio = 1; - job->vcodec = HB_VCODEC_FFMPEG; + job->vcodec = HB_VCODEC_FFMPEG_MPEG4; job->vquality = -1.0; job->vbitrate = 1000; job->pass = 0; diff --git a/libhb/work.c b/libhb/work.c index c8caff7b8..e8c2a4e1e 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -264,8 +264,12 @@ void hb_display_job_info( hb_job_t * job ) /* Video encoder */ switch( job->vcodec ) { - case HB_VCODEC_FFMPEG: - hb_log( " + encoder: FFmpeg" ); + case HB_VCODEC_FFMPEG_MPEG4: + hb_log( " + encoder: FFmpeg MPEG-4" ); + break; + + case HB_VCODEC_FFMPEG_MPEG2: + hb_log( " + encoder: FFmpeg MPEG-2" ); break; case HB_VCODEC_X264: @@ -452,7 +456,7 @@ static void do_job( hb_job_t * job ) { hb_set_anamorphic_size(job, &job->width, &job->height, &job->anamorphic.par_width, &job->anamorphic.par_height); - if( job->vcodec == HB_VCODEC_FFMPEG ) + if( job->vcodec & HB_VCODEC_FFMPEG_MASK ) { /* Just to make working with ffmpeg even more fun, lavc's MPEG-4 encoder can't handle PAR values >= 255, @@ -722,8 +726,13 @@ static void do_job( hb_job_t * job ) /* Video encoder */ switch( job->vcodec ) { - case HB_VCODEC_FFMPEG: + case HB_VCODEC_FFMPEG_MPEG4: w = hb_get_work( WORK_ENCAVCODEC ); + w->codec_param = CODEC_ID_MPEG4; + break; + case HB_VCODEC_FFMPEG_MPEG2: + w = hb_get_work( WORK_ENCAVCODEC ); + w->codec_param = CODEC_ID_MPEG2VIDEO; break; case HB_VCODEC_X264: w = hb_get_work( WORK_ENCX264 ); @@ -993,7 +1002,7 @@ static void do_job( hb_job_t * job ) w = muxer; } - hb_buffer_t * buf_in, * buf_out; + hb_buffer_t * buf_in, * buf_out = NULL; while ( !*job->die && !*w->done && w->status != HB_WORK_DONE ) { |