# HG changeset patch # User michael # Date 1138139846 0 # Node ID a5e0b58b4471b17e50bd34bafebfef14faf365d2 # Parent f02d0b59279c1f9653089fbbe1fac59325fe1eb9 xvid ratecontrol support diff -r f02d0b59279c -r a5e0b58b4471 Makefile --- a/Makefile Tue Jan 24 10:33:14 2006 +0000 +++ b/Makefile Tue Jan 24 21:57:26 2006 +0000 @@ -283,6 +283,7 @@ ifeq ($(CONFIG_XVID),yes) OBJS+= xvidff.o +OBJS+= xvid_rc.o endif ifeq ($(CONFIG_X264),yes) diff -r f02d0b59279c -r a5e0b58b4471 avcodec.h --- a/avcodec.h Tue Jan 24 10:33:14 2006 +0000 +++ b/avcodec.h Tue Jan 24 21:57:26 2006 +0000 @@ -892,6 +892,8 @@ /** obsolete FIXME remove */ int rc_strategy; +#define FF_RC_STRATEGY_XVID 1 + int b_frame_strategy; /** diff -r f02d0b59279c -r a5e0b58b4471 mpegvideo.h --- a/mpegvideo.h Tue Jan 24 10:33:14 2006 +0000 +++ b/mpegvideo.h Tue Jan 24 21:57:26 2006 +0000 @@ -83,12 +83,14 @@ int i_tex_bits; int p_tex_bits; int misc_bits; + int header_bits; uint64_t expected_bits; int new_pict_type; float new_qscale; int mc_mb_var_sum; int mb_var_sum; int i_count; + int skip_count; int f_code; int b_code; }RateControlEntry; @@ -116,6 +118,9 @@ uint64_t qscale_sum[5]; int frame_count[5]; int last_non_b_pict_type; + + void *non_lavc_opaque; ///< context for non lavc rc code (for example xvid) + float dry_run_qscale; ///< for xvid rc }RateControlContext; /** @@ -983,4 +988,8 @@ int ff_vbv_update(MpegEncContext *s, int frame_size); void ff_get_2pass_fcode(MpegEncContext *s); +int ff_xvid_rate_control_init(MpegEncContext *s); +void ff_xvid_rate_control_uninit(MpegEncContext *s); +float ff_xvid_rate_estimate_qscale(MpegEncContext *s, int dry_run); + #endif /* AVCODEC_MPEGVIDEO_H */ diff -r f02d0b59279c -r a5e0b58b4471 ratecontrol.c --- a/ratecontrol.c Tue Jan 24 10:33:14 2006 +0000 +++ b/ratecontrol.c Tue Jan 24 21:57:26 2006 +0000 @@ -38,10 +38,10 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce, double rate_factor, int frame_num); void ff_write_pass1_stats(MpegEncContext *s){ - snprintf(s->avctx->stats_out, 256, "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d;\n", + snprintf(s->avctx->stats_out, 256, "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d skipcount:%d hbits:%d;\n", s->current_picture_ptr->display_picture_number, s->current_picture_ptr->coded_picture_number, s->pict_type, s->current_picture.quality, s->i_tex_bits, s->p_tex_bits, s->mv_bits, s->misc_bits, - s->f_code, s->b_code, s->current_picture.mc_mb_var_sum, s->current_picture.mb_var_sum, s->i_count); + s->f_code, s->b_code, s->current_picture.mc_mb_var_sum, s->current_picture.mb_var_sum, s->i_count, s->skip_count, s->header_bits); } int ff_rate_control_init(MpegEncContext *s) @@ -107,16 +107,21 @@ assert(picture_number < rcc->num_entries); rce= &rcc->entry[picture_number]; - e+=sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d", + e+=sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%d var:%d icount:%d skipcount:%d hbits:%d", &rce->pict_type, &rce->qscale, &rce->i_tex_bits, &rce->p_tex_bits, &rce->mv_bits, &rce->misc_bits, - &rce->f_code, &rce->b_code, &rce->mc_mb_var_sum, &rce->mb_var_sum, &rce->i_count); - if(e!=12){ + &rce->f_code, &rce->b_code, &rce->mc_mb_var_sum, &rce->mb_var_sum, &rce->i_count, &rce->skip_count, &rce->header_bits); + if(e!=14){ av_log(s->avctx, AV_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); return -1; } + p= next; } + //FIXME maybe move to end + if((s->flags&CODEC_FLAG_PASS2) && s->avctx->rc_strategy == FF_RC_STRATEGY_XVID) + return ff_xvid_rate_control_init(s); + if(init_pass2(s) < 0) return -1; } @@ -181,6 +186,9 @@ emms_c(); av_freep(&rcc->entry); + + if((s->flags&CODEC_FLAG_PASS2) && s->avctx->rc_strategy == FF_RC_STRATEGY_XVID) + ff_xvid_rate_control_uninit(s); } static inline double qp2bits(RateControlEntry *rce, double qp){ @@ -640,6 +648,9 @@ Picture * const pic= &s->current_picture; emms_c(); + if((s->flags&CODEC_FLAG_PASS2) && s->avctx->rc_strategy == FF_RC_STRATEGY_XVID) + return ff_xvid_rate_estimate_qscale(s, dry_run); + get_qminmax(&qmin, &qmax, s, pict_type); fps= 1/av_q2d(s->avctx->time_base); diff -r f02d0b59279c -r a5e0b58b4471 xvid_rc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xvid_rc.c Tue Jan 24 21:57:26 2006 +0000 @@ -0,0 +1,137 @@ +/* + * xvid Rate control wrapper for lavc video encoders + * + * Copyright (c) 2006 Michael Niedermayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include "avcodec.h" +//#include "dsputil.h" +#include "mpegvideo.h" + +#undef NDEBUG +#include + +extern unsigned int xvid_debug; + +int ff_xvid_rate_control_init(MpegEncContext *s){ + char *tmp_name; + int fd, i; + xvid_plg_create_t xvid_plg_create; + xvid_plugin_2pass2_t xvid_2pass2; + +//xvid_debug=-1; + + tmp_name= av_strdup("/tmp/xvidrc.XXXXXX"); + fd = mkstemp(tmp_name); + if(fd < 0){ + strcpy(tmp_name, "./xvidrc.XXXXXX"); + fd = mkstemp(tmp_name); + } + + for(i=0; irc_context.num_entries - s->max_b_frames; i++){ + static const char *frame_types = " ipbs"; + char tmp[256]; + RateControlEntry *rce; + + rce= &s->rc_context.entry[i]; + + snprintf(tmp, sizeof(tmp), "%c %d %d %d %d %d %d\n", + frame_types[rce->pict_type], (int)lrintf(rce->qscale / FF_QP2LAMBDA), rce->i_count, s->mb_num - rce->i_count - rce->skip_count, + rce->skip_count, (rce->i_tex_bits + rce->p_tex_bits + rce->mv_bits + rce->misc_bits+7)/8, (rce->header_bits+7)/8); + + write(fd, tmp, strlen(tmp)); + } + + close(fd); + + memset(&xvid_2pass2, 0, sizeof(xvid_2pass2)); + xvid_2pass2.version= XVID_MAKE_VERSION(1,1,0); + xvid_2pass2.filename= tmp_name; + xvid_2pass2.bitrate= s->avctx->bit_rate; + xvid_2pass2.vbv_size= s->avctx->rc_buffer_size; + xvid_2pass2.vbv_maxrate= s->avctx->rc_max_rate; + xvid_2pass2.vbv_initial= s->avctx->rc_initial_buffer_occupancy; + + memset(&xvid_plg_create, 0, sizeof(xvid_plg_create)); + xvid_plg_create.version= XVID_MAKE_VERSION(1,1,0); + xvid_plg_create.fbase= s->avctx->time_base.den; + xvid_plg_create.fincr= s->avctx->time_base.num; + xvid_plg_create.param= &xvid_2pass2; + + return xvid_plugin_2pass2(NULL, XVID_PLG_CREATE, &xvid_plg_create, &s->rc_context.non_lavc_opaque); +} + +float ff_xvid_rate_estimate_qscale(MpegEncContext *s, int dry_run){ + xvid_plg_data_t xvid_plg_data; + + memset(&xvid_plg_data, 0, sizeof(xvid_plg_data)); + xvid_plg_data.version= XVID_MAKE_VERSION(1,1,0); + xvid_plg_data.width = s->width; + xvid_plg_data.height= s->height; + xvid_plg_data.mb_width = s->mb_width; + xvid_plg_data.mb_height= s->mb_height; + xvid_plg_data.fbase= s->avctx->time_base.den; + xvid_plg_data.fincr= s->avctx->time_base.num; + xvid_plg_data.min_quant[0]= s->avctx->qmin; + xvid_plg_data.min_quant[1]= s->avctx->qmin; + xvid_plg_data.min_quant[2]= s->avctx->qmin; //FIXME i/b factor & offset + xvid_plg_data.max_quant[0]= s->avctx->qmax; + xvid_plg_data.max_quant[1]= s->avctx->qmax; + xvid_plg_data.max_quant[2]= s->avctx->qmax; //FIXME i/b factor & offset + xvid_plg_data.bquant_offset = s->avctx->b_quant_offset; + xvid_plg_data.bquant_ratio = 100 * s->avctx->b_quant_factor; + +#if 0 + xvid_plg_data.stats.hlength= X +#endif + + if(!s->rc_context.dry_run_qscale){ + if(s->picture_number){ + xvid_plg_data.length= + xvid_plg_data.stats.length= (s->frame_bits + 7)/8; + xvid_plg_data.frame_num= s->picture_number - 1; + xvid_plg_data.quant= s->qscale; + + xvid_plg_data.type= s->last_pict_type; + if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_AFTER, &xvid_plg_data, NULL)){ + av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_AFTER, ...) FAILED\n"); + return -1; + } + } + xvid_plg_data.frame_num= s->picture_number; + xvid_plg_data.quant= 0; + if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_BEFORE, &xvid_plg_data, NULL)){ + av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_BEFORE, ...) FAILED\n"); + return -1; + } + s->rc_context.dry_run_qscale= xvid_plg_data.quant; + } + xvid_plg_data.quant= s->rc_context.dry_run_qscale; + if(!dry_run) + s->rc_context.dry_run_qscale= 0; + + return xvid_plg_data.quant * FF_QP2LAMBDA; +} + +void ff_xvid_rate_control_uninit(MpegEncContext *s){ + xvid_plg_destroy_t xvid_plg_destroy; + + xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_DESTROY, &xvid_plg_destroy, NULL); +} +