mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
4243da4ff4
This is possible, because every given FFCodec has to implement exactly one of these. Doing so decreases sizeof(FFCodec) and therefore decreases the size of the binary. Notice that in case of position-independent code the decrease is in .data.rel.ro, so that this translates to decreased memory consumption. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
431 lines
15 KiB
C
431 lines
15 KiB
C
/*
|
|
* TwinVQ decoder
|
|
* Copyright (c) 2009 Vitor Sessak
|
|
*
|
|
* 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 <math.h>
|
|
#include <stdint.h>
|
|
|
|
#include "libavutil/channel_layout.h"
|
|
#include "avcodec.h"
|
|
#include "codec_internal.h"
|
|
#include "get_bits.h"
|
|
#include "twinvq.h"
|
|
#include "metasound_data.h"
|
|
#include "twinvq_data.h"
|
|
|
|
static const TwinVQModeTab mode_08_08 = {
|
|
{
|
|
{ 8, bark_tab_s08_64, 10, tab.fcb08s, 1, 5, tab.cb0808s0, tab.cb0808s1, 18 },
|
|
{ 2, bark_tab_m08_256, 20, tab.fcb08m, 2, 5, tab.cb0808m0, tab.cb0808m1, 16 },
|
|
{ 1, bark_tab_l08_512, 30, tab.fcb08l, 3, 6, tab.cb0808l0, tab.cb0808l1, 17 }
|
|
},
|
|
512, 12, ff_metasound_lsp8, 1, 5, 3, 3, tab.shape08, 8, 28, 20, 6, 40
|
|
};
|
|
|
|
static const TwinVQModeTab mode_11_08 = {
|
|
{
|
|
{ 8, bark_tab_s11_64, 10, tab.fcb11s, 1, 5, tab.cb1108s0, tab.cb1108s1, 29 },
|
|
{ 2, bark_tab_m11_256, 20, tab.fcb11m, 2, 5, tab.cb1108m0, tab.cb1108m1, 24 },
|
|
{ 1, bark_tab_l11_512, 30, tab.fcb11l, 3, 6, tab.cb1108l0, tab.cb1108l1, 27 }
|
|
},
|
|
512, 16, ff_metasound_lsp11, 1, 6, 4, 3, tab.shape11, 9, 36, 30, 7, 90
|
|
};
|
|
|
|
static const TwinVQModeTab mode_11_10 = {
|
|
{
|
|
{ 8, bark_tab_s11_64, 10, tab.fcb11s, 1, 5, tab.cb1110s0, tab.cb1110s1, 21 },
|
|
{ 2, bark_tab_m11_256, 20, tab.fcb11m, 2, 5, tab.cb1110m0, tab.cb1110m1, 18 },
|
|
{ 1, bark_tab_l11_512, 30, tab.fcb11l, 3, 6, tab.cb1110l0, tab.cb1110l1, 20 }
|
|
},
|
|
512, 16, ff_metasound_lsp11, 1, 6, 4, 3, tab.shape11, 9, 36, 30, 7, 90
|
|
};
|
|
|
|
static const TwinVQModeTab mode_16_16 = {
|
|
{
|
|
{ 8, bark_tab_s16_128, 10, tab.fcb16s, 1, 5, tab.cb1616s0, tab.cb1616s1, 16 },
|
|
{ 2, bark_tab_m16_512, 20, tab.fcb16m, 2, 5, tab.cb1616m0, tab.cb1616m1, 15 },
|
|
{ 1, bark_tab_l16_1024, 30, tab.fcb16l, 3, 6, tab.cb1616l0, tab.cb1616l1, 16 }
|
|
},
|
|
1024, 16, ff_metasound_lsp16, 1, 6, 4, 3, tab.shape16, 9, 56, 60, 7, 180
|
|
};
|
|
|
|
static const TwinVQModeTab mode_22_20 = {
|
|
{
|
|
{ 8, bark_tab_s22_128, 10, tab.fcb22s_1, 1, 6, tab.cb2220s0, tab.cb2220s1, 18 },
|
|
{ 2, bark_tab_m22_512, 20, tab.fcb22m_1, 2, 6, tab.cb2220m0, tab.cb2220m1, 17 },
|
|
{ 1, bark_tab_l22_1024, 32, tab.fcb22l_1, 4, 6, tab.cb2220l0, tab.cb2220l1, 18 }
|
|
},
|
|
1024, 16, ff_metasound_lsp22, 1, 6, 4, 3, tab.shape22_1, 9, 56, 36, 7, 144
|
|
};
|
|
|
|
static const TwinVQModeTab mode_22_24 = {
|
|
{
|
|
{ 8, bark_tab_s22_128, 10, tab.fcb22s_1, 1, 6, tab.cb2224s0, tab.cb2224s1, 15 },
|
|
{ 2, bark_tab_m22_512, 20, tab.fcb22m_1, 2, 6, tab.cb2224m0, tab.cb2224m1, 14 },
|
|
{ 1, bark_tab_l22_1024, 32, tab.fcb22l_1, 4, 6, tab.cb2224l0, tab.cb2224l1, 15 }
|
|
},
|
|
1024, 16, ff_metasound_lsp22, 1, 6, 4, 3, tab.shape22_1, 9, 56, 36, 7, 144
|
|
};
|
|
|
|
static const TwinVQModeTab mode_22_32 = {
|
|
{
|
|
{ 4, bark_tab_s22_128, 10, tab.fcb22s_2, 1, 6, tab.cb2232s0, tab.cb2232s1, 11 },
|
|
{ 2, bark_tab_m22_256, 20, tab.fcb22m_2, 2, 6, tab.cb2232m0, tab.cb2232m1, 11 },
|
|
{ 1, bark_tab_l22_512, 32, tab.fcb22l_2, 4, 6, tab.cb2232l0, tab.cb2232l1, 12 }
|
|
},
|
|
512, 16, tab.lsp22_2, 1, 6, 4, 4, tab.shape22_2, 9, 56, 36, 7, 72
|
|
};
|
|
|
|
static const TwinVQModeTab mode_44_40 = {
|
|
{
|
|
{ 16, bark_tab_s44_128, 10, tab.fcb44s, 1, 6, tab.cb4440s0, tab.cb4440s1, 18 },
|
|
{ 4, bark_tab_m44_512, 20, tab.fcb44m, 2, 6, tab.cb4440m0, tab.cb4440m1, 17 },
|
|
{ 1, bark_tab_l44_2048, 40, tab.fcb44l, 4, 6, tab.cb4440l0, tab.cb4440l1, 17 }
|
|
},
|
|
2048, 20, ff_metasound_lsp44, 1, 6, 4, 4, tab.shape44, 9, 84, 54, 7, 432
|
|
};
|
|
|
|
static const TwinVQModeTab mode_44_48 = {
|
|
{
|
|
{ 16, bark_tab_s44_128, 10, tab.fcb44s, 1, 6, tab.cb4448s0, tab.cb4448s1, 15 },
|
|
{ 4, bark_tab_m44_512, 20, tab.fcb44m, 2, 6, tab.cb4448m0, tab.cb4448m1, 14 },
|
|
{ 1, bark_tab_l44_2048, 40, tab.fcb44l, 4, 6, tab.cb4448l0, tab.cb4448l1, 14 }
|
|
},
|
|
2048, 20, ff_metasound_lsp44, 1, 6, 4, 4, tab.shape44, 9, 84, 54, 7, 432
|
|
};
|
|
|
|
/**
|
|
* Evaluate a * b / 400 rounded to the nearest integer. When, for example,
|
|
* a * b == 200 and the nearest integer is ill-defined, use a table to emulate
|
|
* the following broken float-based implementation used by the binary decoder:
|
|
*
|
|
* @code
|
|
* static int very_broken_op(int a, int b)
|
|
* {
|
|
* static float test; // Ugh, force gcc to do the division first...
|
|
*
|
|
* test = a / 400.0;
|
|
* return b * test + 0.5;
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @note if this function is replaced by just ROUNDED_DIV(a * b, 400.0), the
|
|
* stddev between the original file (before encoding with Yamaha encoder) and
|
|
* the decoded output increases, which leads one to believe that the encoder
|
|
* expects exactly this broken calculation.
|
|
*/
|
|
static int very_broken_op(int a, int b)
|
|
{
|
|
int x = a * b + 200;
|
|
int size;
|
|
const uint8_t *rtab;
|
|
|
|
if (x % 400 || b % 5)
|
|
return x / 400;
|
|
|
|
x /= 400;
|
|
|
|
size = tabs[b / 5].size;
|
|
rtab = tabs[b / 5].tab;
|
|
return x - rtab[size * av_log2(2 * (x - 1) / size) + (x - 1) % size];
|
|
}
|
|
|
|
/**
|
|
* Sum to data a periodic peak of a given period, width and shape.
|
|
*
|
|
* @param period the period of the peak divided by 400.0
|
|
*/
|
|
static void add_peak(int period, int width, const float *shape,
|
|
float ppc_gain, float *speech, int len)
|
|
{
|
|
int i, j;
|
|
|
|
const float *shape_end = shape + len;
|
|
int center;
|
|
|
|
// First peak centered around zero
|
|
for (i = 0; i < width / 2; i++)
|
|
speech[i] += ppc_gain * *shape++;
|
|
|
|
for (i = 1; i < ROUNDED_DIV(len, width); i++) {
|
|
center = very_broken_op(period, i);
|
|
for (j = -width / 2; j < (width + 1) / 2; j++)
|
|
speech[j + center] += ppc_gain * *shape++;
|
|
}
|
|
|
|
// For the last block, be careful not to go beyond the end of the buffer
|
|
center = very_broken_op(period, i);
|
|
for (j = -width / 2; j < (width + 1) / 2 && shape < shape_end; j++)
|
|
speech[j + center] += ppc_gain * *shape++;
|
|
}
|
|
|
|
static void decode_ppc(TwinVQContext *tctx, int period_coef, int g_coef,
|
|
const float *shape, float *speech)
|
|
{
|
|
const TwinVQModeTab *mtab = tctx->mtab;
|
|
int isampf = tctx->avctx->sample_rate / 1000;
|
|
int ibps = tctx->avctx->bit_rate / (1000 * tctx->avctx->ch_layout.nb_channels);
|
|
int min_period = ROUNDED_DIV(40 * 2 * mtab->size, isampf);
|
|
int max_period = ROUNDED_DIV(40 * 2 * mtab->size * 6, isampf);
|
|
int period_range = max_period - min_period;
|
|
float pgain_step = 25000.0 / ((1 << mtab->pgain_bit) - 1);
|
|
float ppc_gain = 1.0 / 8192 *
|
|
twinvq_mulawinv(pgain_step * g_coef +
|
|
pgain_step / 2,
|
|
25000.0, TWINVQ_PGAIN_MU);
|
|
|
|
// This is actually the period multiplied by 400. It is just linearly coded
|
|
// between its maximum and minimum value.
|
|
int period = min_period +
|
|
ROUNDED_DIV(period_coef * period_range,
|
|
(1 << mtab->ppc_period_bit) - 1);
|
|
int width;
|
|
|
|
if (isampf == 22 && ibps == 32) {
|
|
// For some unknown reason, NTT decided to code this case differently...
|
|
width = ROUNDED_DIV((period + 800) * mtab->peak_per2wid,
|
|
400 * mtab->size);
|
|
} else
|
|
width = period * mtab->peak_per2wid / (400 * mtab->size);
|
|
|
|
add_peak(period, width, shape, ppc_gain, speech, mtab->ppc_shape_len);
|
|
}
|
|
|
|
static void dec_bark_env(TwinVQContext *tctx, const uint8_t *in, int use_hist,
|
|
int ch, float *out, float gain,
|
|
enum TwinVQFrameType ftype)
|
|
{
|
|
const TwinVQModeTab *mtab = tctx->mtab;
|
|
int i, j;
|
|
float *hist = tctx->bark_hist[ftype][ch];
|
|
float val = ((const float []) { 0.4, 0.35, 0.28 })[ftype];
|
|
int bark_n_coef = mtab->fmode[ftype].bark_n_coef;
|
|
int fw_cb_len = mtab->fmode[ftype].bark_env_size / bark_n_coef;
|
|
int idx = 0;
|
|
|
|
for (i = 0; i < fw_cb_len; i++)
|
|
for (j = 0; j < bark_n_coef; j++, idx++) {
|
|
float tmp2 = mtab->fmode[ftype].bark_cb[fw_cb_len * in[j] + i] *
|
|
(1.0 / 4096);
|
|
float st = use_hist ? (1.0 - val) * tmp2 + val * hist[idx] + 1.0
|
|
: tmp2 + 1.0;
|
|
|
|
hist[idx] = tmp2;
|
|
if (st < -1.0)
|
|
st = 1.0;
|
|
|
|
twinvq_memset_float(out, st * gain, mtab->fmode[ftype].bark_tab[idx]);
|
|
out += mtab->fmode[ftype].bark_tab[idx];
|
|
}
|
|
}
|
|
|
|
static void read_cb_data(TwinVQContext *tctx, GetBitContext *gb,
|
|
uint8_t *dst, enum TwinVQFrameType ftype)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < tctx->n_div[ftype]; i++) {
|
|
int bs_second_part = (i >= tctx->bits_main_spec_change[ftype]);
|
|
|
|
*dst++ = get_bits(gb, tctx->bits_main_spec[0][ftype][bs_second_part]);
|
|
*dst++ = get_bits(gb, tctx->bits_main_spec[1][ftype][bs_second_part]);
|
|
}
|
|
}
|
|
|
|
static int twinvq_read_bitstream(AVCodecContext *avctx, TwinVQContext *tctx,
|
|
const uint8_t *buf, int buf_size)
|
|
{
|
|
TwinVQFrameData *bits = &tctx->bits[0];
|
|
const TwinVQModeTab *mtab = tctx->mtab;
|
|
int channels = tctx->avctx->ch_layout.nb_channels;
|
|
int sub;
|
|
GetBitContext gb;
|
|
int i, j, k, ret;
|
|
|
|
if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
|
|
return ret;
|
|
skip_bits(&gb, get_bits(&gb, 8));
|
|
|
|
bits->window_type = get_bits(&gb, TWINVQ_WINDOW_TYPE_BITS);
|
|
|
|
if (bits->window_type > 8) {
|
|
av_log(avctx, AV_LOG_ERROR, "Invalid window type, broken sample?\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
bits->ftype = ff_twinvq_wtype_to_ftype_table[tctx->bits[0].window_type];
|
|
|
|
sub = mtab->fmode[bits->ftype].sub;
|
|
|
|
read_cb_data(tctx, &gb, bits->main_coeffs, bits->ftype);
|
|
|
|
for (i = 0; i < channels; i++)
|
|
for (j = 0; j < sub; j++)
|
|
for (k = 0; k < mtab->fmode[bits->ftype].bark_n_coef; k++)
|
|
bits->bark1[i][j][k] =
|
|
get_bits(&gb, mtab->fmode[bits->ftype].bark_n_bit);
|
|
|
|
for (i = 0; i < channels; i++)
|
|
for (j = 0; j < sub; j++)
|
|
bits->bark_use_hist[i][j] = get_bits1(&gb);
|
|
|
|
if (bits->ftype == TWINVQ_FT_LONG) {
|
|
for (i = 0; i < channels; i++)
|
|
bits->gain_bits[i] = get_bits(&gb, TWINVQ_GAIN_BITS);
|
|
} else {
|
|
for (i = 0; i < channels; i++) {
|
|
bits->gain_bits[i] = get_bits(&gb, TWINVQ_GAIN_BITS);
|
|
for (j = 0; j < sub; j++)
|
|
bits->sub_gain_bits[i * sub + j] = get_bits(&gb,
|
|
TWINVQ_SUB_GAIN_BITS);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < channels; i++) {
|
|
bits->lpc_hist_idx[i] = get_bits(&gb, mtab->lsp_bit0);
|
|
bits->lpc_idx1[i] = get_bits(&gb, mtab->lsp_bit1);
|
|
|
|
for (j = 0; j < mtab->lsp_split; j++)
|
|
bits->lpc_idx2[i][j] = get_bits(&gb, mtab->lsp_bit2);
|
|
}
|
|
|
|
if (bits->ftype == TWINVQ_FT_LONG) {
|
|
read_cb_data(tctx, &gb, bits->ppc_coeffs, 3);
|
|
for (i = 0; i < channels; i++) {
|
|
bits->p_coef[i] = get_bits(&gb, mtab->ppc_period_bit);
|
|
bits->g_coef[i] = get_bits(&gb, mtab->pgain_bit);
|
|
}
|
|
}
|
|
|
|
return (get_bits_count(&gb) + 7) / 8;
|
|
}
|
|
|
|
static av_cold int twinvq_decode_init(AVCodecContext *avctx)
|
|
{
|
|
int isampf, ibps, channels;
|
|
TwinVQContext *tctx = avctx->priv_data;
|
|
|
|
if (!avctx->extradata || avctx->extradata_size < 12) {
|
|
av_log(avctx, AV_LOG_ERROR, "Missing or incomplete extradata\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
channels = AV_RB32(avctx->extradata) + 1;
|
|
avctx->bit_rate = AV_RB32(avctx->extradata + 4) * 1000;
|
|
isampf = AV_RB32(avctx->extradata + 8);
|
|
|
|
if (isampf < 8 || isampf > 44) {
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
switch (isampf) {
|
|
case 44:
|
|
avctx->sample_rate = 44100;
|
|
break;
|
|
case 22:
|
|
avctx->sample_rate = 22050;
|
|
break;
|
|
case 11:
|
|
avctx->sample_rate = 11025;
|
|
break;
|
|
default:
|
|
avctx->sample_rate = isampf * 1000;
|
|
break;
|
|
}
|
|
|
|
if (channels <= 0 || channels > TWINVQ_CHANNELS_MAX) {
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported number of channels: %i\n",
|
|
channels);
|
|
return -1;
|
|
}
|
|
av_channel_layout_uninit(&avctx->ch_layout);
|
|
av_channel_layout_default(&avctx->ch_layout, channels);
|
|
|
|
ibps = avctx->bit_rate / (1000 * channels);
|
|
if (ibps < 8 || ibps > 48) {
|
|
av_log(avctx, AV_LOG_ERROR, "Bad bitrate per channel value %d\n", ibps);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
switch ((isampf << 8) + ibps) {
|
|
case (8 << 8) + 8:
|
|
tctx->mtab = &mode_08_08;
|
|
break;
|
|
case (11 << 8) + 8:
|
|
tctx->mtab = &mode_11_08;
|
|
break;
|
|
case (11 << 8) + 10:
|
|
tctx->mtab = &mode_11_10;
|
|
break;
|
|
case (16 << 8) + 16:
|
|
tctx->mtab = &mode_16_16;
|
|
break;
|
|
case (22 << 8) + 20:
|
|
tctx->mtab = &mode_22_20;
|
|
break;
|
|
case (22 << 8) + 24:
|
|
tctx->mtab = &mode_22_24;
|
|
break;
|
|
case (22 << 8) + 32:
|
|
tctx->mtab = &mode_22_32;
|
|
break;
|
|
case (44 << 8) + 40:
|
|
tctx->mtab = &mode_44_40;
|
|
break;
|
|
case (44 << 8) + 48:
|
|
tctx->mtab = &mode_44_48;
|
|
break;
|
|
default:
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"This version does not support %d kHz - %d kbit/s/ch mode.\n",
|
|
isampf, isampf);
|
|
return -1;
|
|
}
|
|
|
|
tctx->codec = TWINVQ_CODEC_VQF;
|
|
tctx->read_bitstream = twinvq_read_bitstream;
|
|
tctx->dec_bark_env = dec_bark_env;
|
|
tctx->decode_ppc = decode_ppc;
|
|
tctx->frame_size = avctx->bit_rate * tctx->mtab->size
|
|
/ avctx->sample_rate + 8;
|
|
tctx->is_6kbps = 0;
|
|
if (avctx->block_align && avctx->block_align * 8LL / tctx->frame_size > 1) {
|
|
av_log(avctx, AV_LOG_ERROR,
|
|
"VQF TwinVQ should have only one frame per packet\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
return ff_twinvq_decode_init(avctx);
|
|
}
|
|
|
|
const FFCodec ff_twinvq_decoder = {
|
|
.p.name = "twinvq",
|
|
.p.long_name = NULL_IF_CONFIG_SMALL("VQF TwinVQ"),
|
|
.p.type = AVMEDIA_TYPE_AUDIO,
|
|
.p.id = AV_CODEC_ID_TWINVQ,
|
|
.priv_data_size = sizeof(TwinVQContext),
|
|
.init = twinvq_decode_init,
|
|
.close = ff_twinvq_decode_close,
|
|
FF_CODEC_DECODE_CB(ff_twinvq_decode_frame),
|
|
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
|
|
.p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
|
|
AV_SAMPLE_FMT_NONE },
|
|
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
|
|
};
|