You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
avcodec/mpegvideo: Move ratecontrol-only options to RateControlContext
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
@ -507,21 +507,10 @@ typedef struct MpegEncContext {
|
|||||||
me_cmp_func sse_cmp[2];
|
me_cmp_func sse_cmp[2];
|
||||||
int (*sum_abs_dctelem)(const int16_t *block);
|
int (*sum_abs_dctelem)(const int16_t *block);
|
||||||
|
|
||||||
/**
|
|
||||||
* ratecontrol qmin qmax limiting method
|
|
||||||
* 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax.
|
|
||||||
*/
|
|
||||||
float rc_qsquish;
|
|
||||||
float rc_qmod_amp;
|
|
||||||
int rc_qmod_freq;
|
|
||||||
float rc_initial_cplx;
|
|
||||||
float rc_buffer_aggressivity;
|
|
||||||
float border_masking;
|
float border_masking;
|
||||||
int lmin, lmax;
|
int lmin, lmax;
|
||||||
int vbv_ignore_qmax;
|
int vbv_ignore_qmax;
|
||||||
|
|
||||||
char *rc_eq;
|
|
||||||
|
|
||||||
/* temp buffers for rate control */
|
/* temp buffers for rate control */
|
||||||
float *cplx_tab, *bits_tab;
|
float *cplx_tab, *bits_tab;
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
{ "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }
|
{ "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, .unit = "cmp_func" }
|
||||||
|
|
||||||
#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x)
|
#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x)
|
||||||
|
#define FF_RC_OFFSET(x) offsetof(MpegEncContext, rc_context.x)
|
||||||
#define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
|
#define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
|
||||||
#define FF_MPV_COMMON_OPTS \
|
#define FF_MPV_COMMON_OPTS \
|
||||||
FF_MPV_OPT_CMP_FUNC, \
|
FF_MPV_OPT_CMP_FUNC, \
|
||||||
@ -99,16 +100,16 @@ FF_MPV_OPT_CMP_FUNC, \
|
|||||||
{ "error_rate", "Simulate errors in the bitstream to test error concealment.", \
|
{ "error_rate", "Simulate errors in the bitstream to test error concealment.", \
|
||||||
FF_MPV_OFFSET(error_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\
|
FF_MPV_OFFSET(error_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\
|
||||||
{"qsquish", "how to keep quantizer between qmin and qmax (0 = clip, 1 = use differentiable function)", \
|
{"qsquish", "how to keep quantizer between qmin and qmax (0 = clip, 1 = use differentiable function)", \
|
||||||
FF_MPV_OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \
|
FF_RC_OFFSET(qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \
|
||||||
{"rc_qmod_amp", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
{"rc_qmod_amp", "experimental quantizer modulation", FF_RC_OFFSET(qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
||||||
{"rc_qmod_freq", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \
|
{"rc_qmod_freq", "experimental quantizer modulation", FF_RC_OFFSET(qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \
|
||||||
{"rc_eq", "Set rate control equation. When computing the expression, besides the standard functions " \
|
{"rc_eq", "Set rate control equation. When computing the expression, besides the standard functions " \
|
||||||
"defined in the section 'Expression Evaluation', the following functions are available: " \
|
"defined in the section 'Expression Evaluation', the following functions are available: " \
|
||||||
"bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " \
|
"bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " \
|
||||||
"fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", \
|
"fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", \
|
||||||
FF_MPV_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \
|
FF_RC_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \
|
||||||
{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_MPV_OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_RC_OFFSET(initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
||||||
{"rc_buf_aggressivity", "currently useless", FF_MPV_OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
{"rc_buf_aggressivity", "currently useless", FF_RC_OFFSET(buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
||||||
{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \
|
||||||
{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \
|
{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \
|
||||||
{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \
|
{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \
|
||||||
|
@ -182,10 +182,10 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce,
|
|||||||
get_qminmax(&qmin, &qmax, s, pict_type);
|
get_qminmax(&qmin, &qmax, s, pict_type);
|
||||||
|
|
||||||
/* modulation */
|
/* modulation */
|
||||||
if (s->rc_qmod_freq &&
|
if (rcc->qmod_freq &&
|
||||||
frame_num % s->rc_qmod_freq == 0 &&
|
frame_num % rcc->qmod_freq == 0 &&
|
||||||
pict_type == AV_PICTURE_TYPE_P)
|
pict_type == AV_PICTURE_TYPE_P)
|
||||||
q *= s->rc_qmod_amp;
|
q *= rcc->qmod_amp;
|
||||||
|
|
||||||
/* buffer overflow/underflow protection */
|
/* buffer overflow/underflow protection */
|
||||||
if (buffer_size) {
|
if (buffer_size) {
|
||||||
@ -198,7 +198,7 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce,
|
|||||||
d = 1.0;
|
d = 1.0;
|
||||||
else if (d < 0.0001)
|
else if (d < 0.0001)
|
||||||
d = 0.0001;
|
d = 0.0001;
|
||||||
q *= pow(d, 1.0 / s->rc_buffer_aggressivity);
|
q *= pow(d, 1.0 / rcc->buffer_aggressivity);
|
||||||
|
|
||||||
q_limit = bits2qp(rce,
|
q_limit = bits2qp(rce,
|
||||||
FFMAX((min_rate - buffer_size + rcc->buffer_index) *
|
FFMAX((min_rate - buffer_size + rcc->buffer_index) *
|
||||||
@ -218,7 +218,7 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce,
|
|||||||
d = 1.0;
|
d = 1.0;
|
||||||
else if (d < 0.0001)
|
else if (d < 0.0001)
|
||||||
d = 0.0001;
|
d = 0.0001;
|
||||||
q /= pow(d, 1.0 / s->rc_buffer_aggressivity);
|
q /= pow(d, 1.0 / rcc->buffer_aggressivity);
|
||||||
|
|
||||||
q_limit = bits2qp(rce,
|
q_limit = bits2qp(rce,
|
||||||
FFMAX(rcc->buffer_index *
|
FFMAX(rcc->buffer_index *
|
||||||
@ -234,8 +234,8 @@ static double modify_qscale(MpegEncContext *s, const RateControlEntry *rce,
|
|||||||
}
|
}
|
||||||
ff_dlog(s, "q:%f max:%f min:%f size:%f index:%f agr:%f\n",
|
ff_dlog(s, "q:%f max:%f min:%f size:%f index:%f agr:%f\n",
|
||||||
q, max_rate, min_rate, buffer_size, rcc->buffer_index,
|
q, max_rate, min_rate, buffer_size, rcc->buffer_index,
|
||||||
s->rc_buffer_aggressivity);
|
rcc->buffer_aggressivity);
|
||||||
if (s->rc_qsquish == 0.0 || qmin == qmax) {
|
if (rcc->qsquish == 0.0 || qmin == qmax) {
|
||||||
if (q < qmin)
|
if (q < qmin)
|
||||||
q = qmin;
|
q = qmin;
|
||||||
else if (q > qmax)
|
else if (q > qmax)
|
||||||
@ -295,7 +295,7 @@ static double get_qscale(MpegEncContext *s, RateControlEntry *rce,
|
|||||||
|
|
||||||
bits = av_expr_eval(rcc->rc_eq_eval, const_values, rce);
|
bits = av_expr_eval(rcc->rc_eq_eval, const_values, rce);
|
||||||
if (isnan(bits)) {
|
if (isnan(bits)) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", s->rc_eq);
|
av_log(s->avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", rcc->rc_eq);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,11 +541,11 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = av_expr_parse(&rcc->rc_eq_eval,
|
res = av_expr_parse(&rcc->rc_eq_eval,
|
||||||
s->rc_eq ? s->rc_eq : "tex^qComp",
|
rcc->rc_eq ? rcc->rc_eq : "tex^qComp",
|
||||||
const_names, func1_names, func1,
|
const_names, func1_names, func1,
|
||||||
NULL, NULL, 0, s->avctx);
|
NULL, NULL, 0, s->avctx);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", s->rc_eq);
|
av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", rcc->rc_eq);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,9 +649,9 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* init stuff with the user specified complexity */
|
/* init stuff with the user specified complexity */
|
||||||
if (s->rc_initial_cplx) {
|
if (rcc->initial_cplx) {
|
||||||
for (i = 0; i < 60 * 30; i++) {
|
for (i = 0; i < 60 * 30; i++) {
|
||||||
double bits = s->rc_initial_cplx * (i / 10000.0 + 1.0) * s->mb_num;
|
double bits = rcc->initial_cplx * (i / 10000.0 + 1.0) * s->mb_num;
|
||||||
RateControlEntry rce;
|
RateControlEntry rce;
|
||||||
|
|
||||||
if (i % ((s->gop_size + 3) / 4) == 0)
|
if (i % ((s->gop_size + 3) / 4) == 0)
|
||||||
@ -701,6 +701,7 @@ av_cold void ff_rate_control_uninit(RateControlContext *rcc)
|
|||||||
{
|
{
|
||||||
emms_c();
|
emms_c();
|
||||||
|
|
||||||
|
// rc_eq is always managed via an AVOption and therefore not freed here.
|
||||||
av_expr_free(rcc->rc_eq_eval);
|
av_expr_free(rcc->rc_eq_eval);
|
||||||
rcc->rc_eq_eval = NULL;
|
rcc->rc_eq_eval = NULL;
|
||||||
av_freep(&rcc->entry);
|
av_freep(&rcc->entry);
|
||||||
|
@ -77,6 +77,17 @@ typedef struct RateControlContext{
|
|||||||
int frame_count[5];
|
int frame_count[5];
|
||||||
int last_non_b_pict_type;
|
int last_non_b_pict_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ratecontrol qmin qmax limiting method
|
||||||
|
* 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax.
|
||||||
|
*/
|
||||||
|
float qsquish;
|
||||||
|
float qmod_amp;
|
||||||
|
int qmod_freq;
|
||||||
|
float initial_cplx;
|
||||||
|
float buffer_aggressivity;
|
||||||
|
|
||||||
|
char *rc_eq;
|
||||||
struct AVExpr *rc_eq_eval;
|
struct AVExpr *rc_eq_eval;
|
||||||
}RateControlContext;
|
}RateControlContext;
|
||||||
|
|
||||||
|
@ -2118,7 +2118,7 @@ static const AVOption options[] = {
|
|||||||
"defined in the section 'Expression Evaluation', the following functions are available: "
|
"defined in the section 'Expression Evaluation', the following functions are available: "
|
||||||
"bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv "
|
"bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv "
|
||||||
"fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.",
|
"fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.",
|
||||||
OFFSET(m.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE },
|
OFFSET(m.rc_context.rc_eq), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE },
|
||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user