161 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			161 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * This file is part of FFmpeg.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * FFmpeg is free software; you can redistribute it and/or
							 | 
						||
| 
								 | 
							
								 * modify it under the terms of the GNU Lesser General Public
							 | 
						||
| 
								 | 
							
								 * License as published by the Free Software Foundation; either
							 | 
						||
| 
								 | 
							
								 * version 2.1 of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * FFmpeg is distributed in the hope that it will be useful,
							 | 
						||
| 
								 | 
							
								 * but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						||
| 
								 | 
							
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
							 | 
						||
| 
								 | 
							
								 * Lesser General Public License for more details.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * You should have received a copy of the GNU Lesser General Public
							 | 
						||
| 
								 | 
							
								 * License along with FFmpeg; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "tx_priv.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int ff_tx_type_is_mdct(enum AVTXType type)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    switch (type) {
							 | 
						||
| 
								 | 
							
								    case AV_TX_FLOAT_MDCT:
							 | 
						||
| 
								 | 
							
								    case AV_TX_DOUBLE_MDCT:
							 | 
						||
| 
								 | 
							
								    case AV_TX_INT32_MDCT:
							 | 
						||
| 
								 | 
							
								        return 1;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        return 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Calculates the modular multiplicative inverse, not fast, replace */
							 | 
						||
| 
								 | 
							
								static av_always_inline int mulinv(int n, int m)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    n = n % m;
							 | 
						||
| 
								 | 
							
								    for (int x = 1; x < m; x++)
							 | 
						||
| 
								 | 
							
								        if (((n * x) % m) == 1)
							 | 
						||
| 
								 | 
							
								            return x;
							 | 
						||
| 
								 | 
							
								    av_assert0(0); /* Never reached */
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Guaranteed to work for any n, m where gcd(n, m) == 1 */
							 | 
						||
| 
								 | 
							
								int ff_tx_gen_compound_mapping(AVTXContext *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int *in_map, *out_map;
							 | 
						||
| 
								 | 
							
								    const int n     = s->n;
							 | 
						||
| 
								 | 
							
								    const int m     = s->m;
							 | 
						||
| 
								 | 
							
								    const int inv   = s->inv;
							 | 
						||
| 
								 | 
							
								    const int len   = n*m;
							 | 
						||
| 
								 | 
							
								    const int m_inv = mulinv(m, n);
							 | 
						||
| 
								 | 
							
								    const int n_inv = mulinv(n, m);
							 | 
						||
| 
								 | 
							
								    const int mdct  = ff_tx_type_is_mdct(s->type);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!(s->pfatab = av_malloc(2*len*sizeof(*s->pfatab))))
							 | 
						||
| 
								 | 
							
								        return AVERROR(ENOMEM);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    in_map  = s->pfatab;
							 | 
						||
| 
								 | 
							
								    out_map = s->pfatab + n*m;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Ruritanian map for input, CRT map for output, can be swapped */
							 | 
						||
| 
								 | 
							
								    for (int j = 0; j < m; j++) {
							 | 
						||
| 
								 | 
							
								        for (int i = 0; i < n; i++) {
							 | 
						||
| 
								 | 
							
								            /* Shifted by 1 to simplify MDCTs */
							 | 
						||
| 
								 | 
							
								            in_map[j*n + i] = ((i*m + j*n) % len) << mdct;
							 | 
						||
| 
								 | 
							
								            out_map[(i*m*m_inv + j*n*n_inv) % len] = i*m + j;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Change transform direction by reversing all ACs */
							 | 
						||
| 
								 | 
							
								    if (inv) {
							 | 
						||
| 
								 | 
							
								        for (int i = 0; i < m; i++) {
							 | 
						||
| 
								 | 
							
								            int *in = &in_map[i*n + 1]; /* Skip the DC */
							 | 
						||
| 
								 | 
							
								            for (int j = 0; j < ((n - 1) >> 1); j++)
							 | 
						||
| 
								 | 
							
								                FFSWAP(int, in[j], in[n - j - 2]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Our 15-point transform is also a compound one, so embed its input map */
							 | 
						||
| 
								 | 
							
								    if (n == 15) {
							 | 
						||
| 
								 | 
							
								        for (int k = 0; k < m; k++) {
							 | 
						||
| 
								 | 
							
								            int tmp[15];
							 | 
						||
| 
								 | 
							
								            memcpy(tmp, &in_map[k*15], 15*sizeof(*tmp));
							 | 
						||
| 
								 | 
							
								            for (int i = 0; i < 5; i++) {
							 | 
						||
| 
								 | 
							
								                for (int j = 0; j < 3; j++)
							 | 
						||
| 
								 | 
							
								                    in_map[k*15 + i*3 + j] = tmp[(i*3 + j*5) % 15];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int ff_tx_gen_ptwo_revtab(AVTXContext *s)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    const int m = s->m, inv = s->inv;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!(s->revtab = av_malloc(m*sizeof(*s->revtab))))
							 | 
						||
| 
								 | 
							
								        return AVERROR(ENOMEM);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /* Default */
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < m; i++) {
							 | 
						||
| 
								 | 
							
								        int k = -split_radix_permutation(i, m, inv) & (m - 1);
							 | 
						||
| 
								 | 
							
								        s->revtab[k] = i;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								av_cold void av_tx_uninit(AVTXContext **ctx)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    if (!(*ctx))
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    av_free((*ctx)->pfatab);
							 | 
						||
| 
								 | 
							
								    av_free((*ctx)->exptab);
							 | 
						||
| 
								 | 
							
								    av_free((*ctx)->revtab);
							 | 
						||
| 
								 | 
							
								    av_free((*ctx)->tmp);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    av_freep(ctx);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type,
							 | 
						||
| 
								 | 
							
								                       int inv, int len, const void *scale, uint64_t flags)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    int err;
							 | 
						||
| 
								 | 
							
								    AVTXContext *s = av_mallocz(sizeof(*s));
							 | 
						||
| 
								 | 
							
								    if (!s)
							 | 
						||
| 
								 | 
							
								        return AVERROR(ENOMEM);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    switch (type) {
							 | 
						||
| 
								 | 
							
								    case AV_TX_FLOAT_FFT:
							 | 
						||
| 
								 | 
							
								    case AV_TX_FLOAT_MDCT:
							 | 
						||
| 
								 | 
							
								        if ((err = ff_tx_init_mdct_fft_float(s, tx, type, inv, len, scale, flags)))
							 | 
						||
| 
								 | 
							
								            goto fail;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case AV_TX_DOUBLE_FFT:
							 | 
						||
| 
								 | 
							
								    case AV_TX_DOUBLE_MDCT:
							 | 
						||
| 
								 | 
							
								        if ((err = ff_tx_init_mdct_fft_double(s, tx, type, inv, len, scale, flags)))
							 | 
						||
| 
								 | 
							
								            goto fail;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case AV_TX_INT32_FFT:
							 | 
						||
| 
								 | 
							
								    case AV_TX_INT32_MDCT:
							 | 
						||
| 
								 | 
							
								        if ((err = ff_tx_init_mdct_fft_int32(s, tx, type, inv, len, scale, flags)))
							 | 
						||
| 
								 | 
							
								            goto fail;
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        err = AVERROR(EINVAL);
							 | 
						||
| 
								 | 
							
								        goto fail;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    *ctx = s;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								fail:
							 | 
						||
| 
								 | 
							
								    av_tx_uninit(&s);
							 | 
						||
| 
								 | 
							
								    *tx = NULL;
							 | 
						||
| 
								 | 
							
								    return err;
							 | 
						||
| 
								 | 
							
								}
							 |