diff --git a/libavutil/tx.h b/libavutil/tx.h index a3d70644e4..55173810ee 100644 --- a/libavutil/tx.h +++ b/libavutil/tx.h @@ -55,7 +55,8 @@ enum AVTXType { * Stride must be a non-zero multiple of sizeof(float). * * NOTE: the inverse transform is half-length, meaning the output will not - * contain redundant data. This is what most codecs work with. + * contain redundant data. This is what most codecs work with. To do a full + * inverse transform, set the AV_TX_FULL_IMDCT flag on init. */ AV_TX_FLOAT_MDCT = 1, @@ -116,6 +117,14 @@ enum AVTXFlags { * May be slower with certain transform types. */ AV_TX_UNALIGNED = 1ULL << 1, + + /** + * Performs a full inverse MDCT rather than leaving out samples that can be + * derived through symmetry. Requires an output array of 'len' floats, + * rather than the usual 'len/2' floats. + * Ignored for all transforms but inverse MDCTs. + */ + AV_TX_FULL_IMDCT = 1ULL << 2, }; /** diff --git a/libavutil/tx_priv.h b/libavutil/tx_priv.h index 0b40234355..1d4245e71b 100644 --- a/libavutil/tx_priv.h +++ b/libavutil/tx_priv.h @@ -121,6 +121,10 @@ struct AVTXContext { int *pfatab; /* Input/Output mapping for compound transforms */ int *revtab; /* Input mapping for power of two transforms */ int *inplace_idx; /* Required indices to revtab for in-place transforms */ + + av_tx_fn top_tx; /* Used for computing transforms derived from other + * transforms, like full-length iMDCTs and RDFTs. + * NOTE: Do NOT use this to mix assembly with C code. */ }; /* Checks if type is an MDCT */ diff --git a/libavutil/tx_template.c b/libavutil/tx_template.c index b3532c1c5e..a68a84dcd5 100644 --- a/libavutil/tx_template.c +++ b/libavutil/tx_template.c @@ -875,6 +875,24 @@ static void naive_mdct(AVTXContext *s, void *_dst, void *_src, } } +static void full_imdct_wrapper_fn(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + int len = s->m*s->n*4; + int len2 = len >> 1; + int len4 = len >> 2; + FFTSample *dst = _dst; + + s->top_tx(s, dst + len4, _src, stride); + + stride /= sizeof(*dst); + + for (int i = 0; i < len4; i++) { + dst[ i*stride] = -dst[(len2 - i - 1)*stride]; + dst[(len - i - 1)*stride] = dst[(len2 + i + 0)*stride]; + } +} + static int gen_mdct_exptab(AVTXContext *s, int len4, double scale) { const double theta = (scale < 0 ? len4 : 0) + 1.0/8.0; @@ -942,6 +960,10 @@ int TX_NAME(ff_tx_init_mdct_fft)(AVTXContext *s, av_tx_fn *tx, if (is_mdct) { s->scale = *((SCALE_TYPE *)scale); *tx = inv ? naive_imdct : naive_mdct; + if (inv && (flags & AV_TX_FULL_IMDCT)) { + s->top_tx = *tx; + *tx = full_imdct_wrapper_fn; + } } return 0; } @@ -990,8 +1012,13 @@ int TX_NAME(ff_tx_init_mdct_fft)(AVTXContext *s, av_tx_fn *tx, init_cos_tabs(i); } - if (is_mdct) + if (is_mdct) { + if (inv && (flags & AV_TX_FULL_IMDCT)) { + s->top_tx = *tx; + *tx = full_imdct_wrapper_fn; + } return gen_mdct_exptab(s, n*m, *((SCALE_TYPE *)scale)); + } return 0; }