History

lavu/tx: add real to real and real to imaginary RDFT transforms

These are in-place transforms, required for DCT-I and DST-I. Templated as the mod2 variant requires minor modifications, and is required specifically for DCT-I/DST-I.

Lynne committed 3 years ago

Commit 11e22731 parent fba45465 files · +167 −41Browse files

Unified · Split

5 files
  1. doc/APIchanges +3 −0
  2. libavutil/tx.c +15 −3
  3. libavutil/tx.h +10 −0
  4. libavutil/tx_template.c +138 −37
  5. libavutil/version.h +1 −1
doc/APIchanges+3−0
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09 · 1 unmodified line
22
33 API changes, most recent first:
44
5+2023-07-xx - xxxxxxxxxx - lavu 58.18.100 - tx.h
6+ Add AV_TX_REAL_TO_REAL and AV_TX_REAL_TO_IMAGINARY
7+
58 2023-08-18 - xxxxxxxxxx - lavu 58.17.100 - channel_layout.h
69 All AV_CHANNEL_LAYOUT_* macros are now compatible with C++ 17 and older.
710
libavutil/tx.c+15−3
@@ -437,7 +437,9 @@ int ff_tx_decompose_length(int dst[TX_MAX_DECOMPOSITIONS], enum AVTXType type, · 436 unmodified lines
437437
438438 /* Check direction for non-orthogonal codelets */
439439 if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) ||
440− ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv))
440+ ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv) ||
441+ ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_REAL)) && inv) ||
442+ ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_IMAGINARY)) && inv))
441443 continue;
442444
443445 /* Check if the CPU supports the required ISA */
@@ -560,6 +562,10 @@ static void print_flags(AVBPrint *bp, uint64_t f) · 116 unmodified lines
560562 av_bprintf(bp, "%spreshuf", prev > 1 ? sep : "");
561563 if ((f & AV_TX_FULL_IMDCT) && ++prev)
562564 av_bprintf(bp, "%simdct_full", prev > 1 ? sep : "");
565+ if ((f & AV_TX_REAL_TO_REAL) && ++prev)
566+ av_bprintf(bp, "%sreal_to_real", prev > 1 ? sep : "");
567+ if ((f & AV_TX_REAL_TO_IMAGINARY) && ++prev)
568+ av_bprintf(bp, "%sreal_to_imaginary", prev > 1 ? sep : "");
563569 if ((f & FF_TX_ASM_CALL) && ++prev)
564570 av_bprintf(bp, "%sasm_call", prev > 1 ? sep : "");
565571 av_bprintf(bp, "]");
@@ -717,7 +723,11 @@ av_cold int ff_tx_init_subtx(AVTXContext *s, enum AVTXType type, · 151 unmodified lines
717723 uint64_t req_flags = flags;
718724
719725 /* Flags the codelet may require to be present */
720− uint64_t inv_req_mask = AV_TX_FULL_IMDCT | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL;
726+ uint64_t inv_req_mask = AV_TX_FULL_IMDCT |
727+ AV_TX_REAL_TO_REAL |
728+ AV_TX_REAL_TO_IMAGINARY |
729+ FF_TX_PRESHUFFLE |
730+ FF_TX_ASM_CALL;
721731
722732 /* Unaligned codelets are compatible with the aligned flag */
723733 if (req_flags & FF_TX_ALIGNED)
@@ -742,7 +752,9 @@ av_cold int ff_tx_init_subtx(AVTXContext *s, enum AVTXType type, · 18 unmodified lines
742752
743753 /* Check direction for non-orthogonal codelets */
744754 if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) ||
745− ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv))
755+ ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv) ||
756+ ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_REAL)) && inv) ||
757+ ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_IMAGINARY)) && inv))
746758 continue;
747759
748760 /* Check if the requested flags match from both sides */
libavutil/tx.h+10−0
@@ -149,6 +149,16 @@ enum AVTXFlags { · 148 unmodified lines
149149 * Ignored for all transforms but inverse MDCTs.
150150 */
151151 AV_TX_FULL_IMDCT = 1ULL << 2,
152+
153+ /**
154+ * Perform a real to half-complex RDFT.
155+ * Only the real, or imaginary coefficients will
156+ * be output, depending on the flag used. Only available for forward RDFTs.
157+ * Output array must have enough space to hold N complex values
158+ * (regular size for a real to complex transform).
159+ */
160+ AV_TX_REAL_TO_REAL = 1ULL << 3,
161+ AV_TX_REAL_TO_IMAGINARY = 1ULL << 4,
152162 };
153163
154164 /**
libavutil/tx_template.c+138−37
@@ -1613,14 +1613,17 @@ static av_cold int TX_NAME(ff_tx_rdft_init)(AVTXContext *s, · 1612 unmodified lines
16131613 int ret;
16141614 double f, m;
16151615 TXSample *tab;
1616+ int len4 = FFALIGN(len, 4) / 4;
16161617
16171618 s->scale_d = *((SCALE_TYPE *)scale);
16181619 s->scale_f = s->scale_d;
16191620
1621+ flags &= ~(AV_TX_REAL_TO_REAL | AV_TX_REAL_TO_IMAGINARY);
1622+
16201623 if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, NULL, len >> 1, inv, scale)))
16211624 return ret;
16221625
1623− if (!(s->exp = av_mallocz((8 + (len >> 2) - 1)*sizeof(*s->exp))))
1626+ if (!(s->exp = av_mallocz((8 + 2*len4)*sizeof(*s->exp))))
16241627 return AVERROR(ENOMEM);
16251628
16261629 tab = (TXSample *)s->exp;
@@ -1639,17 +1642,20 @@ static av_cold int TX_NAME(ff_tx_rdft_init)(AVTXContext *s, · 12 unmodified lines
16391642 *tab++ = RESCALE( (0.5 - inv) * m);
16401643 *tab++ = RESCALE(-(0.5 - inv) * m);
16411644
1642− for (int i = 0; i < len >> 2; i++)
1645+ for (int i = 0; i < len4; i++)
16431646 *tab++ = RESCALE(cos(i*f));
1644− for (int i = len >> 2; i >= 0; i--)
1645− *tab++ = RESCALE(cos(i*f) * (inv ? +1.0 : -1.0));
1647+
1648+ tab = ((TXSample *)s->exp) + len4 + 8;
1649+
1650+ for (int i = 0; i < len4; i++)
1651+ *tab++ = RESCALE(cos(((float)len/4.0 - (float)i + 0)*f) * (inv ? +1.0 : -1.0));
16461652
16471653 return 0;
16481654 }
16491655
1650−#define DECL_RDFT(name, inv) \
1651−static void TX_NAME(ff_tx_rdft_ ##name)(AVTXContext *s, void *_dst, \
1652− void *_src, ptrdiff_t stride) \
1656+#define DECL_RDFT(n, inv) \
1657+static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \
1658+ void *_src, ptrdiff_t stride) \
16531659 { \
16541660 const int len2 = s->len >> 1; \
16551661 const int len4 = s->len >> 2; \
@@ -1698,40 +1704,131 @@ static void TX_NAME(ff_tx_rdft_ ##name)(AVTXContext *s, void *_dst, \ · 42 unmodified lines
16981704 data[len2].re = data[0].im; \
16991705 data[ 0].im = data[len2].im = 0; \
17001706 } \
1701−}
1707+} \
1708+ \
1709+static const FFTXCodelet TX_NAME(ff_tx_rdft_ ##n## _def) = { \
1710+ .name = TX_NAME_STR("rdft_" #n), \
1711+ .function = TX_NAME(ff_tx_rdft_ ##n), \
1712+ .type = TX_TYPE(RDFT), \
1713+ .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE | \
1714+ (inv ? FF_TX_INVERSE_ONLY : FF_TX_FORWARD_ONLY), \
1715+ .factors = { 4, TX_FACTOR_ANY }, \
1716+ .nb_factors = 2, \
1717+ .min_len = 4, \
1718+ .max_len = TX_LEN_UNLIMITED, \
1719+ .init = TX_NAME(ff_tx_rdft_init), \
1720+ .cpu_flags = FF_TX_CPU_FLAGS_ALL, \
1721+ .prio = FF_TX_PRIO_BASE, \
1722+};
17021723
1703−DECL_RDFT(r2c, 0)
1704−DECL_RDFT(c2r, 1)
1724+DECL_RDFT(r2c, 0)
1725+DECL_RDFT(c2r, 1)
17051726
1706−static const FFTXCodelet TX_NAME(ff_tx_rdft_r2c_def) = {
1707− .name = TX_NAME_STR("rdft_r2c"),
1708− .function = TX_NAME(ff_tx_rdft_r2c),
1709− .type = TX_TYPE(RDFT),
1710− .flags = AV_TX_UNALIGNED | AV_TX_INPLACE |
1711− FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY,
1712− .factors = { 2, TX_FACTOR_ANY },
1713− .nb_factors = 2,
1714− .min_len = 2,
1715− .max_len = TX_LEN_UNLIMITED,
1716− .init = TX_NAME(ff_tx_rdft_init),
1717− .cpu_flags = FF_TX_CPU_FLAGS_ALL,
1718− .prio = FF_TX_PRIO_BASE,
1727+#define DECL_RDFT_HALF(n, mode, mod2) \
1728+static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \
1729+ void *_src, ptrdiff_t stride) \
1730+{ \
1731+ const int len = s->len; \
1732+ const int len2 = len >> 1; \
1733+ const int len4 = len >> 2; \
1734+ const int aligned_len4 = FFALIGN(len, 4)/4; \
1735+ const TXSample *fact = (void *)s->exp; \
1736+ const TXSample *tcos = fact + 8; \
1737+ const TXSample *tsin = tcos + aligned_len4; \
1738+ TXComplex *data = _dst; \
1739+ TXSample *out = _dst; /* Half-complex is forward-only */ \
1740+ TXSample tmp_dc; \
1741+ av_unused TXSample tmp_mid; \
1742+ TXSample tmp[4]; \
1743+ TXComplex sf, sl; \
1744+ \
1745+ s->fn[0](&s->sub[0], _dst, _src, sizeof(TXComplex)); \
1746+ \
1747+ tmp_dc = data[0].re; \
1748+ data[ 0].re = tmp_dc + data[0].im; \
1749+ tmp_dc = tmp_dc - data[0].im; \
1750+ \
1751+ data[ 0].re = MULT(fact[0], data[ 0].re); \
1752+ tmp_dc = MULT(fact[1], tmp_dc); \
1753+ data[len4].re = MULT(fact[2], data[len4].re); \
1754+ \
1755+ if (!mod2) { \
1756+ data[len4].im = MULT(fact[3], data[len4].im); \
1757+ } else { \
1758+ sf = data[len4]; \
1759+ sl = data[len4 + 1]; \
1760+ if (mode == AV_TX_REAL_TO_REAL) \
1761+ tmp[0] = MULT(fact[4], (sf.re + sl.re)); \
1762+ else \
1763+ tmp[0] = MULT(fact[5], (sf.im - sl.im)); \
1764+ tmp[1] = MULT(fact[6], (sf.im + sl.im)); \
1765+ tmp[2] = MULT(fact[7], (sf.re - sl.re)); \
1766+ \
1767+ if (mode == AV_TX_REAL_TO_REAL) { \
1768+ tmp[3] = tmp[1]*tcos[len4] - tmp[2]*tsin[len4]; \
1769+ tmp_mid = (tmp[0] - tmp[3]); \
1770+ } else { \
1771+ tmp[3] = tmp[1]*tsin[len4] + tmp[2]*tcos[len4]; \
1772+ tmp_mid = (tmp[0] + tmp[3]); \
1773+ } \
1774+ } \
1775+ \
1776+ /* NOTE: unrolling this breaks non-mod8 lengths */ \
1777+ for (int i = 1; i <= len4; i++) { \
1778+ TXSample tmp[4]; \
1779+ TXComplex sf = data[i]; \
1780+ TXComplex sl = data[len2 - i]; \
1781+ \
1782+ if (mode == AV_TX_REAL_TO_REAL) \
1783+ tmp[0] = MULT(fact[4], (sf.re + sl.re)); \
1784+ else \
1785+ tmp[0] = MULT(fact[5], (sf.im - sl.im)); \
1786+ \
1787+ tmp[1] = MULT(fact[6], (sf.im + sl.im)); \
1788+ tmp[2] = MULT(fact[7], (sf.re - sl.re)); \
1789+ \
1790+ if (mode == AV_TX_REAL_TO_REAL) { \
1791+ tmp[3] = tmp[1]*tcos[i] - tmp[2]*tsin[i]; \
1792+ out[i] = (tmp[0] + tmp[3]); \
1793+ out[len - i] = (tmp[0] - tmp[3]); \
1794+ } else { \
1795+ tmp[3] = tmp[1]*tsin[i] + tmp[2]*tcos[i]; \
1796+ out[i - 1] = (tmp[3] - tmp[0]); \
1797+ out[len - i - 1] = (tmp[0] + tmp[3]); \
1798+ } \
1799+ } \
1800+ \
1801+ for (int i = 1; i < (len4 + (mode == AV_TX_REAL_TO_IMAGINARY)); i++) \
1802+ out[len2 - i] = out[len - i]; \
1803+ \
1804+ if (mode == AV_TX_REAL_TO_REAL) { \
1805+ out[len2] = tmp_dc; \
1806+ if (mod2) \
1807+ out[len4 + 1] = tmp_mid; \
1808+ } else if (mod2) { \
1809+ out[len4] = tmp_mid; \
1810+ } \
1811+} \
1812+ \
1813+static const FFTXCodelet TX_NAME(ff_tx_rdft_ ##n## _def) = { \
1814+ .name = TX_NAME_STR("rdft_" #n), \
1815+ .function = TX_NAME(ff_tx_rdft_ ##n), \
1816+ .type = TX_TYPE(RDFT), \
1817+ .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | mode | \
1818+ FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, \
1819+ .factors = { 2 + 2*(!mod2), TX_FACTOR_ANY }, \
1820+ .nb_factors = 2, \
1821+ .min_len = 2 + 2*(!mod2), \
1822+ .max_len = TX_LEN_UNLIMITED, \
1823+ .init = TX_NAME(ff_tx_rdft_init), \
1824+ .cpu_flags = FF_TX_CPU_FLAGS_ALL, \
1825+ .prio = FF_TX_PRIO_BASE, \
17191826 };
17201827
1721−static const FFTXCodelet TX_NAME(ff_tx_rdft_c2r_def) = {
1722− .name = TX_NAME_STR("rdft_c2r"),
1723− .function = TX_NAME(ff_tx_rdft_c2r),
1724− .type = TX_TYPE(RDFT),
1725− .flags = AV_TX_UNALIGNED | AV_TX_INPLACE |
1726− FF_TX_OUT_OF_PLACE | FF_TX_INVERSE_ONLY,
1727− .factors = { 2, TX_FACTOR_ANY },
1728− .nb_factors = 2,
1729− .min_len = 2,
1730− .max_len = TX_LEN_UNLIMITED,
1731− .init = TX_NAME(ff_tx_rdft_init),
1732− .cpu_flags = FF_TX_CPU_FLAGS_ALL,
1733− .prio = FF_TX_PRIO_BASE,
1734−};
1828+DECL_RDFT_HALF(r2r, AV_TX_REAL_TO_REAL, 0)
1829+DECL_RDFT_HALF(r2r_mod2, AV_TX_REAL_TO_REAL, 1)
1830+DECL_RDFT_HALF(r2i, AV_TX_REAL_TO_IMAGINARY, 0)
1831+DECL_RDFT_HALF(r2i_mod2, AV_TX_REAL_TO_IMAGINARY, 1)
17351832
17361833 static av_cold int TX_NAME(ff_tx_dct_init)(AVTXContext *s,
17371834 const FFTXCodelet *cd,
@@ -1997,6 +2094,10 @@ const FFTXCodelet * const TX_NAME(ff_tx_codelet_list)[] = { · 259 unmodified lines
19972094 &TX_NAME(ff_tx_mdct_naive_inv_def),
19982095 &TX_NAME(ff_tx_mdct_inv_full_def),
19992096 &TX_NAME(ff_tx_rdft_r2c_def),
2097+ &TX_NAME(ff_tx_rdft_r2r_def),
2098+ &TX_NAME(ff_tx_rdft_r2r_mod2_def),
2099+ &TX_NAME(ff_tx_rdft_r2i_def),
2100+ &TX_NAME(ff_tx_rdft_r2i_mod2_def),
20002101 &TX_NAME(ff_tx_rdft_c2r_def),
20012102 &TX_NAME(ff_tx_dctII_def),
20022103 &TX_NAME(ff_tx_dctIII_def),
libavutil/version.h+1−1
@@ -79,7 +79,7 @@ · 78 unmodified lines
7979 */
8080
8181 #define LIBAVUTIL_VERSION_MAJOR 58
82−#define LIBAVUTIL_VERSION_MINOR 17
82+#define LIBAVUTIL_VERSION_MINOR 18
8383 #define LIBAVUTIL_VERSION_MICRO 100
8484
8585 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t