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
2 2
3API changes, most recent first:3API changes, most recent first:
4 4
52023-07-xx - xxxxxxxxxx - lavu 58.18.100 - tx.h
6 Add AV_TX_REAL_TO_REAL and AV_TX_REAL_TO_IMAGINARY
7
52023-08-18 - xxxxxxxxxx - lavu 58.17.100 - channel_layout.h82023-08-18 - xxxxxxxxxx - lavu 58.17.100 - channel_layout.h
6 All AV_CHANNEL_LAYOUT_* macros are now compatible with C++ 17 and older.9 All AV_CHANNEL_LAYOUT_* macros are now compatible with C++ 17 and older.
7 10
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
437 437
438 /* Check direction for non-orthogonal codelets */438 /* Check direction for non-orthogonal codelets */
439 if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) ||439 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))
441 continue;443 continue;
442 444
443 /* Check if the CPU supports the required ISA */445 /* Check if the CPU supports the required ISA */
@@ -560,6 +562,10 @@ static void print_flags(AVBPrint *bp, uint64_t f) · 116 unmodified lines
560 av_bprintf(bp, "%spreshuf", prev > 1 ? sep : "");562 av_bprintf(bp, "%spreshuf", prev > 1 ? sep : "");
561 if ((f & AV_TX_FULL_IMDCT) && ++prev)563 if ((f & AV_TX_FULL_IMDCT) && ++prev)
562 av_bprintf(bp, "%simdct_full", prev > 1 ? sep : "");564 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 : "");
563 if ((f & FF_TX_ASM_CALL) && ++prev)569 if ((f & FF_TX_ASM_CALL) && ++prev)
564 av_bprintf(bp, "%sasm_call", prev > 1 ? sep : "");570 av_bprintf(bp, "%sasm_call", prev > 1 ? sep : "");
565 av_bprintf(bp, "]");571 av_bprintf(bp, "]");
@@ -717,7 +723,11 @@ av_cold int ff_tx_init_subtx(AVTXContext *s, enum AVTXType type, · 151 unmodified lines
717 uint64_t req_flags = flags;723 uint64_t req_flags = flags;
718 724
719 /* Flags the codelet may require to be present */725 /* 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;
721 731
722 /* Unaligned codelets are compatible with the aligned flag */732 /* Unaligned codelets are compatible with the aligned flag */
723 if (req_flags & FF_TX_ALIGNED)733 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
742 752
743 /* Check direction for non-orthogonal codelets */753 /* Check direction for non-orthogonal codelets */
744 if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) ||754 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))
746 continue;758 continue;
747 759
748 /* Check if the requested flags match from both sides */760 /* Check if the requested flags match from both sides */
libavutil/tx.h+10−0
@@ -149,6 +149,16 @@ enum AVTXFlags { · 148 unmodified lines
149 * Ignored for all transforms but inverse MDCTs.149 * Ignored for all transforms but inverse MDCTs.
150 */150 */
151 AV_TX_FULL_IMDCT = 1ULL << 2,151 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,
152};162};
153 163
154/**164/**
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
1613 int ret;1613 int ret;
1614 double f, m;1614 double f, m;
1615 TXSample *tab;1615 TXSample *tab;
1616 int len4 = FFALIGN(len, 4) / 4;
1616 1617
1617 s->scale_d = *((SCALE_TYPE *)scale);1618 s->scale_d = *((SCALE_TYPE *)scale);
1618 s->scale_f = s->scale_d;1619 s->scale_f = s->scale_d;
1619 1620
1621 flags &= ~(AV_TX_REAL_TO_REAL | AV_TX_REAL_TO_IMAGINARY);
1622
1620 if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, NULL, len >> 1, inv, scale)))1623 if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, NULL, len >> 1, inv, scale)))
1621 return ret;1624 return ret;
1622 1625
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))))
1624 return AVERROR(ENOMEM);1627 return AVERROR(ENOMEM);
1625 1628
1626 tab = (TXSample *)s->exp;1629 tab = (TXSample *)s->exp;
@@ -1639,17 +1642,20 @@ static av_cold int TX_NAME(ff_tx_rdft_init)(AVTXContext *s, · 12 unmodified lines
1639 *tab++ = RESCALE( (0.5 - inv) * m);1642 *tab++ = RESCALE( (0.5 - inv) * m);
1640 *tab++ = RESCALE(-(0.5 - inv) * m);1643 *tab++ = RESCALE(-(0.5 - inv) * m);
1641 1644
1642 for (int i = 0; i < len >> 2; i++)1645 for (int i = 0; i < len4; i++)
1643 *tab++ = RESCALE(cos(i*f));1646 *tab++ = RESCALE(cos(i*f));
1644 for (int i = len >> 2; i >= 0; i--)1647
1645 *tab++ = RESCALE(cos(i*f) * (inv ? +1.0 : -1.0));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));
1646 1652
1647 return 0;1653 return 0;
1648}1654}
1649 1655
1650#define DECL_RDFT(name, inv) \1656#define DECL_RDFT(n, inv) \
1651static void TX_NAME(ff_tx_rdft_ ##name)(AVTXContext *s, void *_dst, \1657static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \
1652 void *_src, ptrdiff_t stride) \1658 void *_src, ptrdiff_t stride) \
1653{ \1659{ \
1654 const int len2 = s->len >> 1; \1660 const int len2 = s->len >> 1; \
1655 const int len4 = s->len >> 2; \1661 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
1698 data[len2].re = data[0].im; \1704 data[len2].re = data[0].im; \
1699 data[ 0].im = data[len2].im = 0; \1705 data[ 0].im = data[len2].im = 0; \
1700 } \1706 } \
1701}1707} \
1708 \
1709static 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};
1702 1723
1703DECL_RDFT(r2c, 0)1724DECL_RDFT(r2c, 0)
1704DECL_RDFT(c2r, 1)1725DECL_RDFT(c2r, 1)
1705 1726
1706static const FFTXCodelet TX_NAME(ff_tx_rdft_r2c_def) = {1727#define DECL_RDFT_HALF(n, mode, mod2) \
1707 .name = TX_NAME_STR("rdft_r2c"),1728static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \
1708 .function = TX_NAME(ff_tx_rdft_r2c),1729 void *_src, ptrdiff_t stride) \
1709 .type = TX_TYPE(RDFT),1730{ \
1710 .flags = AV_TX_UNALIGNED | AV_TX_INPLACE |1731 const int len = s->len; \
1711 FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY,1732 const int len2 = len >> 1; \
1712 .factors = { 2, TX_FACTOR_ANY },1733 const int len4 = len >> 2; \
1713 .nb_factors = 2,1734 const int aligned_len4 = FFALIGN(len, 4)/4; \
1714 .min_len = 2,1735 const TXSample *fact = (void *)s->exp; \
1715 .max_len = TX_LEN_UNLIMITED,1736 const TXSample *tcos = fact + 8; \
1716 .init = TX_NAME(ff_tx_rdft_init),1737 const TXSample *tsin = tcos + aligned_len4; \
1717 .cpu_flags = FF_TX_CPU_FLAGS_ALL,1738 TXComplex *data = _dst; \
1718 .prio = FF_TX_PRIO_BASE,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 \
1813static 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, \
1719};1826};
1720 1827
1721static const FFTXCodelet TX_NAME(ff_tx_rdft_c2r_def) = {1828DECL_RDFT_HALF(r2r, AV_TX_REAL_TO_REAL, 0)
1722 .name = TX_NAME_STR("rdft_c2r"),1829DECL_RDFT_HALF(r2r_mod2, AV_TX_REAL_TO_REAL, 1)
1723 .function = TX_NAME(ff_tx_rdft_c2r),1830DECL_RDFT_HALF(r2i, AV_TX_REAL_TO_IMAGINARY, 0)
1724 .type = TX_TYPE(RDFT),1831DECL_RDFT_HALF(r2i_mod2, AV_TX_REAL_TO_IMAGINARY, 1)
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};
1735 1832
1736static av_cold int TX_NAME(ff_tx_dct_init)(AVTXContext *s,1833static av_cold int TX_NAME(ff_tx_dct_init)(AVTXContext *s,
1737 const FFTXCodelet *cd,1834 const FFTXCodelet *cd,
@@ -1997,6 +2094,10 @@ const FFTXCodelet * const TX_NAME(ff_tx_codelet_list)[] = { · 259 unmodified lines
1997 &TX_NAME(ff_tx_mdct_naive_inv_def),2094 &TX_NAME(ff_tx_mdct_naive_inv_def),
1998 &TX_NAME(ff_tx_mdct_inv_full_def),2095 &TX_NAME(ff_tx_mdct_inv_full_def),
1999 &TX_NAME(ff_tx_rdft_r2c_def),2096 &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),
2000 &TX_NAME(ff_tx_rdft_c2r_def),2101 &TX_NAME(ff_tx_rdft_c2r_def),
2001 &TX_NAME(ff_tx_dctII_def),2102 &TX_NAME(ff_tx_dctII_def),
2002 &TX_NAME(ff_tx_dctIII_def),2103 &TX_NAME(ff_tx_dctIII_def),
libavutil/version.h+1−1
@@ -79,7 +79,7 @@ · 78 unmodified lines
79 */79 */
80 80
81#define LIBAVUTIL_VERSION_MAJOR 5881#define LIBAVUTIL_VERSION_MAJOR 58
82#define LIBAVUTIL_VERSION_MINOR 1782#define LIBAVUTIL_VERSION_MINOR 18
83#define LIBAVUTIL_VERSION_MICRO 10083#define LIBAVUTIL_VERSION_MICRO 100
84 84
85#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \85#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