mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-24 02:09:03 +03:00
avcodec/aaccoder_nmr, aacenc, aacpsy: -aac_rc abr
-aac_rc cbr|abr (default cbr). ABR runs the nd-target quality solve with the set-point owned by a slow rate servo, and joins VBR as a quality-target mode in the psy model (fixed-reference PE reduction, quality attack map, broadband mask floor). The servo integrates the log rate error but applies it to the nd set-point in rare, discrete, calm-gated steps. The set-point must be quasi-static: any drift on content timescales moves lambda, and with it band/PNS/scalefactor state, tracking sections in antiphase and coarsening exactly what needs bits - measured 2x worse than a fixed target at equal mean rate. Locally this mode IS fixed-target VBR; rate honesty converges on the minutes scale. Bootstrap. The set-point is seeded from the VBR calibration anchor (one constant, NMR_VBR_ANCHOR: the two are required to agree, and moving only one copy made ABR overshoot its rate target by up to 9%). After ~2s of fast rate measurement off a representative window (an all-transient head reads over-target and would coarsen the very content that needs bits), an open-loop jump over the measured loop gain (~ -0.24 log2 rate per target unit) corrects the seed's per-content error, applied at 1.2x - the estimator's own inverse warm-up factor, since the EMA is seeded on target (a cold start must not read as a fake deficit) and so recovers only ~82% of the error. One correction is not enough whatever the gain estimate, because the 0.24 loop gain is only nominal: the boot re-arms while the rate is still off, up to a bounded number of times, re-measuring each time, and re-seeds the estimator on target rather than to zero (a zero estimate pins the integrator at its clip via log2f(0) and reads as a 100% deficit to the fill in the same frame). Its settle window sits below the stepper's hold, or the stepper resets the shared counter first and the re-arm never fires. Every set-point correction is glided in at ~0.5 log2-units/s rather than stepped: a one-frame noise-floor jump at a fixed stream time (the boot lands at ~2s in every stream) is audible against revealing content even at step sizes the corpus cannot see. Bits-fill. Under the long-run target, an easy frame is topped up toward the ask by moving lambda finer only - the quality target is a floor, never traded away. It spends the rate the user asked for on sub-mask margin the nd statistic cannot see (it clips at -4/band); without it, stat-transparent content caps the rate below any ask. The fill runs from frame one and fades continuously as the rate EMA converges (a boot-gated fill flipped regimes at ~2s, an audible quality step), follows the psy PE demand shape, and is slew-bounded, writing the lambda continuity state from long frames only instead of free-diving up to 64x per frame. The un-booted stream head behaves CBR-like until the servo takes over (love.flac: >6k energy had swung 0.61-1.83x vs the source at frame rate while the head ran 25% under the ask). The reachable-range clamps do not track the calibration anchor: their floors are set by the stat's -4/band sub-mask clip. A floor at -1.65 railed the servo on easy content (male_speech at a 128k ask pinned at the clamp with a 10% standing deficit); -3.0 keeps 384k asks reachable without the stall. Easy content can still fall short of very high asks (main_theme: 196k at a 256k ask) - there is no padding. The coarse clamp is a quality guard: set-points past it buy little rate for a lot of quality (2.5 -> 6.0 at a 48k ask: -5% rate, +32% Zimtohrli), so asks below about 56 kbps stereo land above the ask (24k/32k asks: ~40k). The documentation points those rates at CBR. Rate accuracy against the -b:a ask: corpus bias mean|err| worst IgorC-3 -1.3% 2.2% -11.8% IgorC-1 +1.1% 2.0% +5.0% 32 random -0.3% 2.2% -10.0% A 4.5-minute concatenation of the IgorC-3 samples lands at 128.2 kbps on a 128k ask. castanets/velvet ABR beat CBR; ABR corpus 0.00060 at 126k. -aac_rc is documented, and fate-aac-nmr-abr-encode pins the per-packet sizes through the servo's boot.
This commit is contained in:
@@ -85,6 +85,22 @@ and much faster at higher bitrates.
|
||||
|
||||
@end table
|
||||
|
||||
@item aac_rc
|
||||
Rate-control mode of the @samp{nmr} coder when a bitrate is set with @option{b}
|
||||
(other coders ignore it; @option{q} takes precedence). Possible values:
|
||||
|
||||
@table @samp
|
||||
@item cbr
|
||||
Constant bitrate within the decoder's bit reservoir. This is the default.
|
||||
|
||||
@item abr
|
||||
Average bitrate: a constant-quality target, as in VBR, whose set-point a slow
|
||||
servo moves to meet @option{b} over the length of the stream. Local quality
|
||||
stays constant, so short files and individual passages can deviate from the
|
||||
requested rate; the average converges over minutes rather than seconds. Below
|
||||
roughly 56 kbps stereo the rate lands above the request; use @samp{cbr} there.
|
||||
@end table
|
||||
|
||||
@item aac_ms
|
||||
Sets mid/side coding mode. The default value of "auto" will automatically use
|
||||
M/S with bands which will benefit from such coding. Can be forced for all bands
|
||||
|
||||
@@ -91,18 +91,45 @@
|
||||
|
||||
/* Quality-target calibration anchor: the nd set-point of -q:a 1, which lands
|
||||
* near 128-136 kbps stereo on the tuning corpora with the q ladder's own
|
||||
* bandwidth. It moved -2.1 -> -0.75 with the quality-target mask floor
|
||||
* (PSY_THRFL_QUALITY), which lowers thr_real and so lifts the whole statistic.
|
||||
* The reachable-range clamp is set by the stat's -4/band sub-mask clip, which
|
||||
* the mask floor does not touch: targets below it are asymptotically
|
||||
* unreachable - the bisect rails at the finest lambda, the frame exceeds the
|
||||
* decoder buffer and the outer re-encode loop never converges. */
|
||||
* bandwidth. The ABR servo seeds off the same constant (referenced to 81.5
|
||||
* kbps/ch, where it measured before the bandwidth retune; the boot corrects
|
||||
* the per-content seed error), so they are one constant. It moved
|
||||
* -2.1 -> -0.75 with the quality-target mask floor (PSY_THRFL_QUALITY), which
|
||||
* lowers thr_real and so lifts the whole statistic.
|
||||
* The reachable-range clamps did NOT move
|
||||
* with it: their floors are set by the stat's -4/band sub-mask clip, which the
|
||||
* mask floor does not touch. Targets below them are asymptotically unreachable
|
||||
* - the bisect rails at the finest lambda, the frame exceeds the decoder buffer
|
||||
* and the outer re-encode loop never converges (the 384k stall). Raising them
|
||||
* with the anchor railed the ABR servo instead: it wanted a finer target to
|
||||
* meet its rate ask on easy content and could not ask for one. */
|
||||
#define NMR_VBR_ANCHOR (-0.75f)
|
||||
#define NMR_VBR_TMIN (-3.8f)
|
||||
/* ABR set-point range. The coarse end is a quality guard: set-points past it
|
||||
* buy little rate for a lot of quality (2.5 -> 6.0 at a 48k ask: -5% rate,
|
||||
* +32% Zimtohrli), so asks below ~56 kbps stereo land above the ask - CBR
|
||||
* is the mode for those rates. At the fine end, easy content can fall short
|
||||
* of very high asks (no padding). */
|
||||
#define NMR_ABR_TMIN (-3.0f)
|
||||
#define NMR_ABR_TMAX 2.5f
|
||||
|
||||
/* ABR servo: integrator gain on the log rate error, rate EMA weight after the
|
||||
* boot, set-point step size and minimum frames between steps */
|
||||
#define NMR_ABR_K 0.003f
|
||||
#define NMR_ABR_EMA 0.0023f
|
||||
#define NMR_ABR_STEP 0.15f
|
||||
#define NMR_ABR_HOLD 120
|
||||
/* ABR boot: open-loop correction gain over the nominal loop gain, the rate
|
||||
* error that re-arms it, the re-arm budget and the settle time before one */
|
||||
#define NMR_ABR_BOOT_GAIN 1.2f
|
||||
#define NMR_ABR_TOL 0.02f
|
||||
#define NMR_ABR_BOOTS 6
|
||||
#define NMR_ABR_SETTLE 100
|
||||
|
||||
/* VBR shorts: the measured stat inflation counts fully once this share of
|
||||
* the frame's energy sits above 6 kHz */
|
||||
#define NMR_INFL_HF 0.10f
|
||||
|
||||
/* Reservoir half-window (bits/ch); swept 512/1536/3072, 1536 optimal. */
|
||||
#define NMR_CBR_BUF 1536
|
||||
/* Slew limit on the FINAL operating lambda per frame; bits deviate instead,
|
||||
@@ -754,9 +781,14 @@ static void nmr_solve_group(AVCodecContext *avctx, AACEncContext *s,
|
||||
}
|
||||
|
||||
int vbr = (avctx->flags & AV_CODEC_FLAG_QSCALE) && s->nmr;
|
||||
int abr = !vbr && s->options.rc == 1 && avctx->bit_rate > 0 && s->nmr;
|
||||
int vbr_subst = 1;
|
||||
float vbr_t = 0.0f;
|
||||
if (vbr) {
|
||||
if (abr) {
|
||||
/* ABR: same quality-target solve, set-point owned by the rate servo */
|
||||
vbr_t = s->nmr->abr_t;
|
||||
vbr = 1;
|
||||
} else if (vbr) {
|
||||
/* nd-target VBR: constant achieved noise-to-mask, bits float. */
|
||||
/* target in log2(dist/real-mask), anchored so -q:a 1 lands near
|
||||
* 128 kbps stereo on the tuning corpus; higher q is finer, each q
|
||||
@@ -1011,6 +1043,48 @@ static void nmr_solve_group(AVCodecContext *avctx, AACEncContext *s,
|
||||
hardcap = FFMAX(hardcap - (int)(FFMAX(s->nmr->side_ema, 0.0f) * chans / s->channels), 256);
|
||||
for (int k = 0; k < nsl; k++)
|
||||
tot += nmr_slot_bits(sl[k], s->nmr->nb[sl[k]->si], NMR_STEP);
|
||||
if (abr && s->nmr->abr_ema < rc_rate_frame) {
|
||||
/* bits-fill: under the long-run target, top an easy frame up
|
||||
* toward the ask by moving lambda FINER only - the quality
|
||||
* target is a floor, never traded away. Spends the rate the
|
||||
* user asked for on sub-mask margin the nd statistic cannot
|
||||
* see (it clips at -4/band); without this, stat-transparent
|
||||
* content caps the rate below any ask. Active from frame one
|
||||
* (the immature EMA reads as a deficit, so the stream head is
|
||||
* held near the ask) and fades continuously as the EMA
|
||||
* converges - a boot-gated fill flips regimes at ~2s, an
|
||||
* audible quality step.
|
||||
* The fill target follows the psy PE demand shape: per-frame
|
||||
* demand carries perceptual information the nd model does not
|
||||
* (the constant-lambda lesson) - and routing it through the
|
||||
* fill keeps the quality floor intact. */
|
||||
float dshape = 1.0f;
|
||||
int fill;
|
||||
if (s->psy.bitres.alloc > 0) {
|
||||
float *aema = &s->nmr->abr_alloc_ema;
|
||||
if (*aema <= 0.0f) *aema = s->psy.bitres.alloc;
|
||||
else *aema += 0.01f * (s->psy.bitres.alloc - *aema);
|
||||
dshape = av_clipf(s->psy.bitres.alloc / *aema, 0.6f, 1.7f);
|
||||
}
|
||||
fill = (int)((rc_rate_frame + (rc_rate_frame - (int)s->nmr->abr_ema)) * dshape) *
|
||||
chans / s->channels;
|
||||
fill = FFMIN3(fill, 3 * rc_rate_frame * chans / s->channels / 2, hardcap);
|
||||
if (tot < fill) {
|
||||
/* the fill dive is the easy-frame operating point: slew it
|
||||
* like any other lambda move and let it carry the
|
||||
* continuity state, or per-frame depth variation reads as
|
||||
* frame-rate HF wobble */
|
||||
float flo = lam / 64.0f;
|
||||
if (*vslew_st > 0.0f)
|
||||
flo = FFMIN(FFMAX(flo, *vslew_st / NMR_SLEW), lam);
|
||||
lam = nmr_solve_slots(s, sl, nsl, NMR_STEP, fill, flo, lam, NMR_RC_ITERS);
|
||||
if (!is8_any)
|
||||
*vslew_st = s->nmr->lam_slew = lam;
|
||||
tot = 0;
|
||||
for (int k = 0; k < nsl; k++)
|
||||
tot += nmr_slot_bits(sl[k], s->nmr->nb[sl[k]->si], NMR_STEP);
|
||||
}
|
||||
}
|
||||
if (tot > hardcap) {
|
||||
lam = nmr_solve_slots(s, sl, nsl, NMR_STEP, hardcap, lam, 1e4f, NMR_RC_ITERS);
|
||||
tot = 0;
|
||||
@@ -1280,7 +1354,7 @@ static void search_for_quantizers_nmr(AVCodecContext *avctx,
|
||||
/* Global-lambda RC: one solve per frame at a servoed centre lambda; the reservoir
|
||||
* holds the long-run mean rate. Bypassed for VBR (-q:a) and the bootstrap frame. */
|
||||
int rc_eligible = !(avctx->flags & AV_CODEC_FLAG_QSCALE) && avctx->bit_rate > 0 &&
|
||||
avctx->bit_rate_tolerance != 0;
|
||||
avctx->bit_rate_tolerance != 0 && s->options.rc == 0;
|
||||
/* Signed reservoir; soft steering (bounded repay + rc_off), hard cap =
|
||||
* legality only. */
|
||||
int rc_rate_frame = avctx->bit_rate * 1024.0 / avctx->sample_rate;
|
||||
@@ -1291,6 +1365,108 @@ static void search_for_quantizers_nmr(AVCodecContext *avctx,
|
||||
|
||||
s->nmr->counted[s->cur_channel] = 0;
|
||||
|
||||
if (s->options.rc == 1 && !(avctx->flags & AV_CODEC_FLAG_QSCALE) &&
|
||||
avctx->bit_rate > 0 && avctx->frame_num != n->abr_frame_num) {
|
||||
/* ABR servo: integrate the log rate error, but apply it to the nd
|
||||
* set-point in RARE, DISCRETE steps. The set-point must be
|
||||
* quasi-static: any drift on content timescales moves lambda, and
|
||||
* with it band/PNS/scalefactor state - measured 2x worse than a
|
||||
* fixed target at equal mean rate. Locally this mode IS fixed-target
|
||||
* VBR; rate honesty converges on the minutes scale. */
|
||||
if (n->abr_frame_num == 0 && n->abr_ema <= 0.0f) {
|
||||
/* seed the set-point from the VBR calibration anchor (see
|
||||
* NMR_VBR_ANCHOR for the 81.5 kbps/ch reference); the servo
|
||||
* trims the rest */
|
||||
n->abr_t = av_clipf(NMR_VBR_ANCHOR - 2.5f * log2f(avctx->bit_rate /
|
||||
(81500.0f * s->channels)), NMR_ABR_TMIN, NMR_ABR_TMAX);
|
||||
n->abr_ema = rc_rate_frame;
|
||||
} else if (s->last_frame_pb_count > 0) {
|
||||
/* bootstrap: fast rate measurement for ~2s, then one open-loop
|
||||
* jump over the measured loop gain (~ -0.24 log2 rate per target
|
||||
* unit) corrects the seed's per-content error; the quasi-static
|
||||
* stepper handles drift from there */
|
||||
/* seed on-target: an EMA warming up from zero reads as a fake
|
||||
* deficit and the fill overspends the whole stream head */
|
||||
if (n->abr_ema <= 0.0f)
|
||||
n->abr_ema = rc_rate_frame;
|
||||
n->abr_ema += (n->abr_booted ? NMR_ABR_EMA : 0.02f) *
|
||||
(s->last_frame_pb_count - n->abr_ema);
|
||||
n->abr_hold++;
|
||||
if (!n->abr_booted) {
|
||||
n->abr_longs += sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE;
|
||||
/* boot only off a REPRESENTATIVE window: an all-transient
|
||||
* head (castanets roll) reads over-target and would coarsen
|
||||
* the very content that needs bits. Time out eventually. */
|
||||
if ((n->abr_hold >= 86 && n->abr_longs >= n->abr_hold / 2) ||
|
||||
n->abr_hold >= 400) {
|
||||
/* glide the seed correction in, never step it: a
|
||||
* one-frame noise-floor jump at a fixed stream time is
|
||||
* audible against revealing content */
|
||||
n->abr_glide = NMR_ABR_BOOT_GAIN * log2f(n->abr_ema / rc_rate_frame) / 0.24f;
|
||||
n->abr_booted = 1;
|
||||
n->abr_boots++;
|
||||
n->abr_hold = 0;
|
||||
}
|
||||
} else {
|
||||
/* Re-arm the open-loop correction while the rate is still
|
||||
* off. One boot leaves a residual whenever the real loop gain
|
||||
* differs from the nominal 0.24, and the estimator is biased
|
||||
* toward the ask by construction (the EMA is seeded ON target
|
||||
* so a cold start cannot read as a deficit), so it understates
|
||||
* the error it is correcting. The quasi-static stepper cannot
|
||||
* drain that inside a track - measured, male_speech ended a
|
||||
* 774-frame file 23% short and still moving. Re-measuring and
|
||||
* firing again converges regardless of the gain estimate, and
|
||||
* keeps the set-point quasi-static: corrections stay rare,
|
||||
* glided, and bounded in number. */
|
||||
if (n->abr_boots < NMR_ABR_BOOTS && n->abr_glide == 0.0f &&
|
||||
n->abr_hold >= NMR_ABR_SETTLE &&
|
||||
fabsf(log2f(n->abr_ema / rc_rate_frame)) > NMR_ABR_TOL) {
|
||||
/* Re-seed the estimator ON target, exactly as the cold
|
||||
* start does - never to zero. The value is read again
|
||||
* before anything re-seeds it: by the integrator below
|
||||
* (log2f(0) is -inf, which pinned the accumulator at its
|
||||
* clip) and by the bits-fill later in this same frame
|
||||
* (a zero EMA reads as a 100% deficit and authorises a
|
||||
* one-frame overspend). Drop the residual integral with
|
||||
* it: it describes the regime being left, and the boot
|
||||
* is about to re-measure that same error open-loop. */
|
||||
n->abr_booted = 0;
|
||||
n->abr_ema = rc_rate_frame;
|
||||
n->abr_acc = 0.0f;
|
||||
n->abr_hold = 0;
|
||||
n->abr_longs = 0;
|
||||
} else {
|
||||
n->abr_acc = av_clipf(n->abr_acc + NMR_ABR_K * log2f(n->abr_ema / rc_rate_frame),
|
||||
-4.0f * NMR_ABR_STEP, 4.0f * NMR_ABR_STEP);
|
||||
/* step in calm stretches (a set-point move during a transient
|
||||
* section coarsens exactly what needs the bits) - but dense
|
||||
* content must not deadlock the servo: after 3x the hold the
|
||||
* step fires regardless. Large errors step at double size;
|
||||
* the remainder carries over instead of being discarded. */
|
||||
if (fabsf(n->abr_acc) >= NMR_ABR_STEP && n->abr_hold >= NMR_ABR_HOLD &&
|
||||
(n->frames_since_short >= 12 || n->abr_hold >= 3 * NMR_ABR_HOLD)) {
|
||||
float ms = NMR_ABR_STEP * (fabsf(n->abr_acc) > 3.0f * NMR_ABR_STEP ? 2.0f : 1.0f);
|
||||
float step = av_clipf(n->abr_acc, -ms, ms);
|
||||
n->abr_glide += step;
|
||||
n->abr_acc -= step;
|
||||
n->abr_hold = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n->abr_glide != 0.0f) {
|
||||
/* drain pending set-point corrections smoothly (~0.5
|
||||
* log2-units/s): the decision stays quasi-static and
|
||||
* calm-gated, only the application glides */
|
||||
float d = av_clipf(n->abr_glide, -0.012f, 0.012f);
|
||||
n->abr_t = av_clipf(n->abr_t + d, NMR_ABR_TMIN, NMR_ABR_TMAX);
|
||||
n->abr_glide -= d;
|
||||
if (fabsf(n->abr_glide) < 1e-4f)
|
||||
n->abr_glide = 0.0f;
|
||||
}
|
||||
}
|
||||
n->abr_frame_num = avctx->frame_num;
|
||||
}
|
||||
if (rc_eligible && !n->rc_fill_seeded) {
|
||||
/* the decoder bit reservoir starts FULL: seed it so the head may frontload */
|
||||
n->rc_fill = rc_bmax;
|
||||
|
||||
@@ -1692,12 +1692,12 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
|
||||
avpkt->size = put_bytes_output(&s->pb);
|
||||
|
||||
/* NMR reports its real operating lambda: the corridor centre in CBR,
|
||||
* the quality-mode slew state in VBR - the lambda of the last long
|
||||
* the quality-mode slew state in VBR/ABR - the lambda of the last long
|
||||
* operating-point solve, which short frames and legality re-solves do
|
||||
* not update (the outer-loop s->lambda is never touched for this coder
|
||||
* and would pin Qavg at its 120 init) */
|
||||
s->lambda_sum += (s->nmr && s->nmr->lam_slew > 0.0f &&
|
||||
(avctx->flags & AV_CODEC_FLAG_QSCALE)) ?
|
||||
((avctx->flags & AV_CODEC_FLAG_QSCALE) || s->options.rc == 1)) ?
|
||||
s->nmr->lam_slew :
|
||||
(s->nmr && s->nmr->lam_rc > 0.0f) ? s->nmr->lam_rc : s->lambda;
|
||||
s->lambda_count++;
|
||||
@@ -1964,7 +1964,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
|
||||
lengths[1] = ff_aac_num_swb_128[s->samplerate_index];
|
||||
for (i = 0; i < s->chan_map[0]; i++)
|
||||
grouping[i] = s->chan_map[i + 1] == TYPE_CPE;
|
||||
s->psy.unbounded_pe = (avctx->flags & AV_CODEC_FLAG_QSCALE) &&
|
||||
s->psy.unbounded_pe = ((avctx->flags & AV_CODEC_FLAG_QSCALE) || s->options.rc == 1) &&
|
||||
s->options.coder == AAC_CODER_NMR;
|
||||
if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths,
|
||||
s->chan_map[0], grouping, s->bandwidth)) < 0)
|
||||
@@ -1991,6 +1991,9 @@ static const AVOption aacenc_options[] = {
|
||||
{"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
|
||||
{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
|
||||
{"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
|
||||
{"aac_rc", "Rate-control mode (NMR coder)", offsetof(AACEncContext, options.rc), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AACENC_FLAGS, .unit = "aac_rc"},
|
||||
{"cbr", "Constant bitrate (corridor + leaky bucket)", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "aac_rc"},
|
||||
{"abr", "Average bitrate (constant-quality target, slow rate servo)", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "aac_rc"},
|
||||
{"aac_nmr_speed", "NMR coder speed level: 0 = slowest/best, higher trades quality for speed", offsetof(AACEncContext, options.nmr_speed), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, AACENC_FLAGS},
|
||||
{"aac_allow_71wide", "Allow non-PCE use of 7.1(wide) channel layout", offsetof(AACEncContext, options.allow_71wide), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AACENC_FLAGS},
|
||||
FF_AAC_PROFILE_OPTS
|
||||
|
||||
@@ -72,6 +72,7 @@ typedef struct AACEncOptions {
|
||||
int intensity_stereo;
|
||||
int nmr_speed; ///< NMR coder speed level: 0 = slowest/best, higher is faster
|
||||
int allow_71wide;
|
||||
int rc; ///< rate-control mode: 0 = cbr (corridor+bucket), 1 = abr (nd-target + slow servo)
|
||||
} AACEncOptions;
|
||||
|
||||
/**
|
||||
@@ -248,6 +249,18 @@ typedef struct AACNMRCurves {
|
||||
float lam_short_ema; ///< smoothed operating lambda of short frames
|
||||
float lam_long_ema; ///< smoothed operating lambda of long frames
|
||||
float lam_floor; ///< lambda min-tracker (snaps down, +2%/frame up): sustained-strain floor; bursty spikes at a comfortable rate cannot raise it
|
||||
|
||||
/* ABR: nd-target set-point servoed to hold the long-run mean rate */
|
||||
float abr_t; ///< current nd target (log2 dist/mask)
|
||||
float abr_glide; ///< pending set-point correction, drained per-frame (no discrete quality steps)
|
||||
float abr_ema; ///< EMA of real frame bits
|
||||
float abr_acc; ///< accumulated set-point correction
|
||||
int abr_hold; ///< frames since the target last stepped
|
||||
int abr_booted; ///< seed correction applied (re-armed while the rate is still off)
|
||||
int abr_boots; ///< open-loop corrections fired so far
|
||||
float abr_alloc_ema; ///< EMA of psy bit demand (fill shaping)
|
||||
int abr_longs; ///< long frames seen during bootstrap
|
||||
int64_t abr_frame_num; ///< once-per-frame servo guard
|
||||
} AACNMRCurves;
|
||||
|
||||
typedef struct AACPCEInfo {
|
||||
|
||||
@@ -332,14 +332,16 @@ static float lame_calc_attack_threshold(int bitrate)
|
||||
/**
|
||||
* LAME psy model specific initialization
|
||||
*/
|
||||
static av_cold void lame_window_init(AacPsyContext *ctx, AVCodecContext *avctx)
|
||||
static av_cold void lame_window_init(FFPsyContext *fctx, AacPsyContext *ctx, AVCodecContext *avctx)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < avctx->ch_layout.nb_channels; i++) {
|
||||
AacPsyChannel *pch = &ctx->ch[i];
|
||||
|
||||
if (avctx->flags & AV_CODEC_FLAG_QSCALE)
|
||||
if ((avctx->flags & AV_CODEC_FLAG_QSCALE) || fctx->unbounded_pe)
|
||||
/* quality-target coders (VBR and ABR) switch windows for quality,
|
||||
* not rate: use the quality attack map regardless of bit_rate */
|
||||
pch->attack_threshold = psy_vbr_map[av_clip(avctx->global_quality / FF_QP2LAMBDA, 0, 10)].st_lrm;
|
||||
else
|
||||
pch->attack_threshold = lame_calc_attack_threshold(avctx->bit_rate / avctx->ch_layout.nb_channels / 1000);
|
||||
@@ -456,7 +458,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) {
|
||||
for (i = 0; i < ctx->avctx->ch_layout.nb_channels; i++)
|
||||
pctx->ch[i].rc_frame_num = -1;
|
||||
|
||||
lame_window_init(pctx, ctx->avctx);
|
||||
lame_window_init(ctx, pctx, ctx->avctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -953,7 +955,7 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
|
||||
* it cannot fail. A band we still choose to code must never be allowed
|
||||
* noise within PSY_THRFL_* dB of its own energy, whatever the hole logic said. */
|
||||
{
|
||||
int qmode = !!(ctx->avctx->flags & AV_CODEC_FLAG_QSCALE);
|
||||
int qmode = ctx->unbounded_pe || (ctx->avctx->flags & AV_CODEC_FLAG_QSCALE);
|
||||
float lim = qmode ? PSY_THRFL_QUALITY : PSY_THRFL_CBR;
|
||||
float knee = qmode ? 0.0f : PSY_THRFL_CBR_KNEE;
|
||||
float lo = ff_exp10f(-lim / 10.0f);
|
||||
|
||||
@@ -268,6 +268,10 @@ fate-aac-yoraw-encode: FUZZ = 17
|
||||
FATE_AAC_ENCODE_TRANSCODE += fate-aac-nmr-vbr-encode
|
||||
fate-aac-nmr-vbr-encode: CMD = transcode wav $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav adts "-af aresample -c:a aac -q:a 8 -t 2" "-c copy"
|
||||
|
||||
# ABR through the rate servo's boot (~2s)
|
||||
FATE_AAC_ENCODE_TRANSCODE += fate-aac-nmr-abr-encode
|
||||
fate-aac-nmr-abr-encode: CMD = transcode wav $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav adts "-af aresample -c:a aac -aac_rc abr -b:a 96k -t 3" "-c copy"
|
||||
|
||||
tests/data/fate/aac-5_1_2.adts: TAG = GEN
|
||||
tests/data/fate/aac-5_1_2.adts: tests/data/asynth-44100-8.wav
|
||||
tests/data/fate/aac-5_1_2.adts: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data/fate
|
||||
|
||||
138
tests/ref/fate/aac-nmr-abr-encode
Normal file
138
tests/ref/fate/aac-nmr-abr-encode
Normal file
@@ -0,0 +1,138 @@
|
||||
8a93613d6b0acab3fc863fda864a48e5 *tests/data/fate/aac-nmr-abr-encode.adts
|
||||
31792 tests/data/fate/aac-nmr-abr-encode.adts
|
||||
#tb 0: 1/28224000
|
||||
#media_type 0: audio
|
||||
#codec_id 0: aac
|
||||
#sample_rate 0: 44100
|
||||
#channel_layout_name 0: stereo
|
||||
0, 0, 0, 655360, 269, 0xfa9b83e0
|
||||
0, 655360, 655360, 655360, 464, 0xa230e9b1
|
||||
0, 1310720, 1310720, 655360, 260, 0x549a7ba3
|
||||
0, 1966080, 1966080, 655360, 262, 0xe5ce7d83
|
||||
0, 2621440, 2621440, 655360, 259, 0x26067677
|
||||
0, 3276800, 3276800, 655360, 261, 0x2bdc7bc4
|
||||
0, 3932160, 3932160, 655360, 244, 0xc16d750e
|
||||
0, 4587520, 4587520, 655360, 252, 0xb09d7762
|
||||
0, 5242880, 5242880, 655360, 263, 0x91157965
|
||||
0, 5898240, 5898240, 655360, 259, 0xb3e972f4
|
||||
0, 6553600, 6553600, 655360, 268, 0xcbe9813d
|
||||
0, 7208960, 7208960, 655360, 252, 0xf9c076f3
|
||||
0, 7864320, 7864320, 655360, 398, 0x2851be3c
|
||||
0, 8519680, 8519680, 655360, 320, 0x166d991d
|
||||
0, 9175040, 9175040, 655360, 408, 0xca4cd36f
|
||||
0, 9830400, 9830400, 655360, 239, 0x78c2742b
|
||||
0, 10485760, 10485760, 655360, 246, 0xca377334
|
||||
0, 11141120, 11141120, 655360, 240, 0x635e7250
|
||||
0, 11796480, 11796480, 655360, 220, 0x3bbd66ae
|
||||
0, 12451840, 12451840, 655360, 210, 0xf244638d
|
||||
0, 13107200, 13107200, 655360, 209, 0x64a6563b
|
||||
0, 13762560, 13762560, 655360, 221, 0xa96762cd
|
||||
0, 14417920, 14417920, 655360, 226, 0x749f66c4
|
||||
0, 15073280, 15073280, 655360, 226, 0xd0eb6387
|
||||
0, 15728640, 15728640, 655360, 223, 0xc3826574
|
||||
0, 16384000, 16384000, 655360, 220, 0x78a86d47
|
||||
0, 17039360, 17039360, 655360, 230, 0xb4446dc3
|
||||
0, 17694720, 17694720, 655360, 215, 0x306f7104
|
||||
0, 18350080, 18350080, 655360, 229, 0x91de69c3
|
||||
0, 19005440, 19005440, 655360, 219, 0x078e672d
|
||||
0, 19660800, 19660800, 655360, 214, 0xb5b766a4
|
||||
0, 20316160, 20316160, 655360, 220, 0x7023610b
|
||||
0, 20971520, 20971520, 655360, 210, 0x182a5ee8
|
||||
0, 21626880, 21626880, 655360, 203, 0xdf3655a9
|
||||
0, 22282240, 22282240, 655360, 231, 0x13d565d0
|
||||
0, 22937600, 22937600, 655360, 229, 0x5e0063f5
|
||||
0, 23592960, 23592960, 655360, 232, 0xf03468e7
|
||||
0, 24248320, 24248320, 655360, 244, 0x882a7785
|
||||
0, 24903680, 24903680, 655360, 236, 0xf8bd7012
|
||||
0, 25559040, 25559040, 655360, 228, 0x1956677a
|
||||
0, 26214400, 26214400, 655360, 266, 0x3e6b81a9
|
||||
0, 26869760, 26869760, 655360, 233, 0x5ab66d73
|
||||
0, 27525120, 27525120, 655360, 244, 0x25b56b66
|
||||
0, 28180480, 28180480, 655360, 184, 0xd9695100
|
||||
0, 28835840, 28835840, 655360, 229, 0x22f771cd
|
||||
0, 29491200, 29491200, 655360, 260, 0xc6fa8312
|
||||
0, 30146560, 30146560, 655360, 256, 0x48197e58
|
||||
0, 30801920, 30801920, 655360, 247, 0xea997935
|
||||
0, 31457280, 31457280, 655360, 239, 0xa22f7015
|
||||
0, 32112640, 32112640, 655360, 259, 0x8b2384c0
|
||||
0, 32768000, 32768000, 655360, 252, 0xd23e790d
|
||||
0, 33423360, 33423360, 655360, 240, 0x25056b8c
|
||||
0, 34078720, 34078720, 655360, 256, 0xab1077f8
|
||||
0, 34734080, 34734080, 655360, 238, 0xd99a6cc5
|
||||
0, 35389440, 35389440, 655360, 223, 0x4ffe6c3f
|
||||
0, 36044800, 36044800, 655360, 222, 0x8c7c5f7a
|
||||
0, 36700160, 36700160, 655360, 231, 0xcc3172bf
|
||||
0, 37355520, 37355520, 655360, 224, 0xc23b68cf
|
||||
0, 38010880, 38010880, 655360, 222, 0xf0986a4d
|
||||
0, 38666240, 38666240, 655360, 233, 0x92a36bc9
|
||||
0, 39321600, 39321600, 655360, 251, 0x11516fb9
|
||||
0, 39976960, 39976960, 655360, 263, 0x0f0b7e11
|
||||
0, 40632320, 40632320, 655360, 408, 0xbf1ccc26
|
||||
0, 41287680, 41287680, 655360, 531, 0xa5690ccd
|
||||
0, 41943040, 41943040, 655360, 308, 0x5eed9716
|
||||
0, 42598400, 42598400, 655360, 277, 0x3668903e
|
||||
0, 43253760, 43253760, 655360, 239, 0x2bab729b
|
||||
0, 43909120, 43909120, 655360, 227, 0x3c8b7095
|
||||
0, 44564480, 44564480, 655360, 190, 0x6c3257ab
|
||||
0, 45219840, 45219840, 655360, 209, 0x19125f77
|
||||
0, 45875200, 45875200, 655360, 196, 0xcec25cec
|
||||
0, 46530560, 46530560, 655360, 250, 0x3e2875d4
|
||||
0, 47185920, 47185920, 655360, 276, 0x37138362
|
||||
0, 47841280, 47841280, 655360, 210, 0x77d55f66
|
||||
0, 48496640, 48496640, 655360, 202, 0x88c06283
|
||||
0, 49152000, 49152000, 655360, 201, 0x364a5f76
|
||||
0, 49807360, 49807360, 655360, 218, 0x38ee6916
|
||||
0, 50462720, 50462720, 655360, 205, 0x017c6140
|
||||
0, 51118080, 51118080, 655360, 205, 0xba40628e
|
||||
0, 51773440, 51773440, 655360, 211, 0x3ab1628d
|
||||
0, 52428800, 52428800, 655360, 208, 0x9b636846
|
||||
0, 53084160, 53084160, 655360, 207, 0xcbd06506
|
||||
0, 53739520, 53739520, 655360, 207, 0x487f6291
|
||||
0, 54394880, 54394880, 655360, 218, 0x7aa870d9
|
||||
0, 55050240, 55050240, 655360, 256, 0x3495754e
|
||||
0, 55705600, 55705600, 655360, 335, 0xd95aa995
|
||||
0, 56360960, 56360960, 655360, 196, 0x54e75268
|
||||
0, 57016320, 57016320, 655360, 209, 0x04de5e1e
|
||||
0, 57671680, 57671680, 655360, 206, 0xa2f463a5
|
||||
0, 58327040, 58327040, 655360, 204, 0xad526074
|
||||
0, 58982400, 58982400, 655360, 209, 0xde2e5aec
|
||||
0, 59637760, 59637760, 655360, 209, 0x8c6d6905
|
||||
0, 60293120, 60293120, 655360, 202, 0x44ca5964
|
||||
0, 60948480, 60948480, 655360, 206, 0xd8685ef3
|
||||
0, 61603840, 61603840, 655360, 209, 0xff6360ce
|
||||
0, 62259200, 62259200, 655360, 207, 0xa9fc61b1
|
||||
0, 62914560, 62914560, 655360, 209, 0x312d6796
|
||||
0, 63569920, 63569920, 655360, 218, 0x4c9f695f
|
||||
0, 64225280, 64225280, 655360, 224, 0x34996723
|
||||
0, 64880640, 64880640, 655360, 234, 0x02096ec5
|
||||
0, 65536000, 65536000, 655360, 246, 0xa63a70c2
|
||||
0, 66191360, 66191360, 655360, 277, 0x8559914c
|
||||
0, 66846720, 66846720, 655360, 240, 0xa2087438
|
||||
0, 67502080, 67502080, 655360, 245, 0xc61a826b
|
||||
0, 68157440, 68157440, 655360, 248, 0xd92a7776
|
||||
0, 68812800, 68812800, 655360, 244, 0xa4517d63
|
||||
0, 69468160, 69468160, 655360, 258, 0x79cb75e2
|
||||
0, 70123520, 70123520, 655360, 274, 0x98708776
|
||||
0, 70778880, 70778880, 655360, 239, 0xcd83750c
|
||||
0, 71434240, 71434240, 655360, 232, 0x05336d82
|
||||
0, 72089600, 72089600, 655360, 234, 0x55847ac8
|
||||
0, 72744960, 72744960, 655360, 234, 0x76da6e4c
|
||||
0, 73400320, 73400320, 655360, 221, 0x919969bf
|
||||
0, 74055680, 74055680, 655360, 223, 0xfbfb69c2
|
||||
0, 74711040, 74711040, 655360, 228, 0xf9e373d7
|
||||
0, 75366400, 75366400, 655360, 224, 0xd0975f50
|
||||
0, 76021760, 76021760, 655360, 234, 0xa66d6e10
|
||||
0, 76677120, 76677120, 655360, 249, 0x2a276d92
|
||||
0, 77332480, 77332480, 655360, 239, 0x53516e65
|
||||
0, 77987840, 77987840, 655360, 270, 0xa6b77886
|
||||
0, 78643200, 78643200, 655360, 274, 0x076d7c58
|
||||
0, 79298560, 79298560, 655360, 269, 0x93fc811b
|
||||
0, 79953920, 79953920, 655360, 239, 0x9dfc73de
|
||||
0, 80609280, 80609280, 655360, 255, 0x6aa47d01
|
||||
0, 81264640, 81264640, 655360, 236, 0x755271f0
|
||||
0, 81920000, 81920000, 655360, 241, 0x8bab73ea
|
||||
0, 82575360, 82575360, 655360, 246, 0xa0ac7c7a
|
||||
0, 83230720, 83230720, 655360, 251, 0x74447d8a
|
||||
0, 83886080, 83886080, 655360, 223, 0xefc36a30
|
||||
0, 84541440, 84541440, 655360, 241, 0x88ab6e54
|
||||
0, 85196800, 85196800, 655360, 191, 0x89b45c00
|
||||
Reference in New Issue
Block a user