From 60784c5360081543ec5a72d806a62b2f6c332dc8 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 10 May 2023 10:41:00 +0200 Subject: [PATCH 1/2] avcodec: remove obscure pseudo synth "decoder" Proper place for synths is in libavfilter. Signed-off-by: Paul B Mahol --- doc/decoders.texi | 8 - libavcodec/Makefile | 1 - libavcodec/allcodecs.c | 1 - libavcodec/codec_desc.c | 2 + libavcodec/codec_id.h | 2 + libavcodec/ffwavesynth.c | 473 ------------------------------------- libavcodec/version_major.h | 1 + 7 files changed, 5 insertions(+), 483 deletions(-) delete mode 100644 libavcodec/ffwavesynth.c diff --git a/doc/decoders.texi b/doc/decoders.texi index 09b8314dd2..1ecd8fe85b 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -240,14 +240,6 @@ correctly by using lavc's old buggy lpc logic for decoding. @end table -@section ffwavesynth - -Internal wave synthesizer. - -This decoder generates wave patterns according to predefined sequences. Its -use is purely internal and the format of the data it accepts is not publicly -documented. - @section libcelt libcelt decoder wrapper. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index b0971ce833..1dec091b21 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -356,7 +356,6 @@ OBJS-$(CONFIG_EXR_ENCODER) += exrenc.o float2half.o OBJS-$(CONFIG_FASTAUDIO_DECODER) += fastaudio.o OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o -OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o OBJS-$(CONFIG_FIC_DECODER) += fic.o OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o OBJS-$(CONFIG_FITS_ENCODER) += fitsenc.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 8eeed34e57..67b9a95e14 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -470,7 +470,6 @@ extern const FFCodec ff_eac3_encoder; extern const FFCodec ff_eac3_decoder; extern const FFCodec ff_evrc_decoder; extern const FFCodec ff_fastaudio_decoder; -extern const FFCodec ff_ffwavesynth_decoder; extern const FFCodec ff_flac_encoder; extern const FFCodec ff_flac_decoder; extern const FFCodec ff_ftr_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index d40977d6b3..b86483871b 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3131,6 +3131,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("codec2 (very low bitrate speech codec)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, +#if FF_API_FFWAVESYNTH_CODECID { .id = AV_CODEC_ID_FFWAVESYNTH, .type = AVMEDIA_TYPE_AUDIO, @@ -3138,6 +3139,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"), .props = AV_CODEC_PROP_INTRA_ONLY, }, +#if FF_API_FFWAVESYNTH_CODECID { .id = AV_CODEC_ID_SONIC, .type = AVMEDIA_TYPE_AUDIO, diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 70800ec20b..299889c15b 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -504,7 +504,9 @@ enum AVCodecID { AV_CODEC_ID_ON2AVC, AV_CODEC_ID_DSS_SP, AV_CODEC_ID_CODEC2, +#if FF_API_WAVESYNTH_CODECID AV_CODEC_ID_FFWAVESYNTH, +#endif AV_CODEC_ID_SONIC, AV_CODEC_ID_SONIC_LS, AV_CODEC_ID_EVRC, diff --git a/libavcodec/ffwavesynth.c b/libavcodec/ffwavesynth.c deleted file mode 100644 index b932326fd0..0000000000 --- a/libavcodec/ffwavesynth.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Wavesynth pseudo-codec - * Copyright (c) 2011 Nicolas George - * - * 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 "libavutil/intreadwrite.h" -#include "libavutil/log.h" -#include "avcodec.h" -#include "codec_internal.h" -#include "decode.h" - - -#define SIN_BITS 14 -#define WS_MAX_CHANNELS 32 -#define INF_TS 0x7FFFFFFFFFFFFFFF - -#define PINK_UNIT 128 - -/* - Format of the extradata and packets - - THIS INFORMATION IS NOT PART OF THE PUBLIC API OR ABI. - IT CAN CHANGE WITHOUT NOTIFICATION. - - All numbers are in little endian. - - The codec extradata define a set of intervals with uniform content. - Overlapping intervals are added together. - - extradata: - uint32 number of intervals - ... intervals - - interval: - int64 start timestamp; time_base must be 1/sample_rate; - start timestamps must be in ascending order - int64 end timestamp - uint32 type - uint32 channels mask - ... additional information, depends on type - - sine interval (type fourcc "SINE"): - int32 start frequency, in 1/(1<<16) Hz - int32 end frequency - int32 start amplitude, 1<<16 is the full amplitude - int32 end amplitude - uint32 start phase, 0 is sin(0), 0x20000000 is sin(pi/2), etc.; - n | (1<<31) means to match the phase of previous channel #n - - pink noise interval (type fourcc "NOIS"): - int32 start amplitude - int32 end amplitude - - The input packets encode the time and duration of the requested segment. - - packet: - int64 start timestamp - int32 duration - -*/ - -enum ws_interval_type { - WS_SINE = MKTAG('S','I','N','E'), - WS_NOISE = MKTAG('N','O','I','S'), -}; - -struct ws_interval { - int64_t ts_start, ts_end; - uint64_t phi0, dphi0, ddphi; - uint64_t amp0, damp; - uint64_t phi, dphi, amp; - uint32_t channels; - enum ws_interval_type type; - int next; -}; - -struct wavesynth_context { - int64_t cur_ts; - int64_t next_ts; - int32_t *sin; - struct ws_interval *inter; - uint32_t dither_state; - uint32_t pink_state; - int32_t pink_pool[PINK_UNIT]; - unsigned pink_need, pink_pos; - int nb_inter; - int cur_inter; - int next_inter; -}; - -#define LCG_A 1284865837 -#define LCG_C 4150755663 -#define LCG_AI 849225893 /* A*AI = 1 [mod 1<<32] */ - -static uint32_t lcg_next(uint32_t *s) -{ - *s = *s * LCG_A + LCG_C; - return *s; -} - -static void lcg_seek(uint32_t *s, uint32_t dt) -{ - uint32_t a, c, t = *s; - - a = LCG_A; - c = LCG_C; - while (dt) { - if (dt & 1) - t = a * t + c; - c *= a + 1; /* coefficients for a double step */ - a *= a; - dt >>= 1; - } - *s = t; -} - -/* Emulate pink noise by summing white noise at the sampling frequency, - * white noise at half the sampling frequency (each value taken twice), - * etc., with a total of 8 octaves. - * This is known as the Voss-McCartney algorithm. */ - -static void pink_fill(struct wavesynth_context *ws) -{ - int32_t vt[7] = { 0 }, v = 0; - int i, j; - - ws->pink_pos = 0; - if (!ws->pink_need) - return; - for (i = 0; i < PINK_UNIT; i++) { - for (j = 0; j < 7; j++) { - if ((i >> j) & 1) - break; - v -= vt[j]; - vt[j] = (int32_t)lcg_next(&ws->pink_state) >> 3; - v += vt[j]; - } - ws->pink_pool[i] = v + ((int32_t)lcg_next(&ws->pink_state) >> 3); - } - lcg_next(&ws->pink_state); /* so we use exactly 256 steps */ -} - -/** - * @return (1<<64) * a / b, without overflow, if a < b - */ -static uint64_t frac64(uint64_t a, uint64_t b) -{ - uint64_t r = 0; - int i; - - if (b < (uint64_t)1 << 32) { /* b small, use two 32-bits steps */ - a <<= 32; - return ((a / b) << 32) | ((a % b) << 32) / b; - } - if (b < (uint64_t)1 << 48) { /* b medium, use four 16-bits steps */ - for (i = 0; i < 4; i++) { - a <<= 16; - r = (r << 16) | (a / b); - a %= b; - } - return r; - } - for (i = 63; i >= 0; i--) { - if (a >= (uint64_t)1 << 63 || a << 1 >= b) { - r |= (uint64_t)1 << i; - a = (a << 1) - b; - } else { - a <<= 1; - } - } - return r; -} - -static uint64_t phi_at(struct ws_interval *in, int64_t ts) -{ - uint64_t dt = ts - (uint64_t)in->ts_start; - uint64_t dt2 = dt & 1 ? /* dt * (dt - 1) / 2 without overflow */ - dt * ((dt - 1) >> 1) : (dt >> 1) * (dt - 1); - return in->phi0 + dt * in->dphi0 + dt2 * in->ddphi; -} - -static void wavesynth_seek(struct wavesynth_context *ws, int64_t ts) -{ - int *last, i; - struct ws_interval *in; - - last = &ws->cur_inter; - for (i = 0; i < ws->nb_inter; i++) { - in = &ws->inter[i]; - if (ts < in->ts_start) - break; - if (ts >= in->ts_end) - continue; - *last = i; - last = &in->next; - in->phi = phi_at(in, ts); - in->dphi = in->dphi0 + (ts - in->ts_start) * in->ddphi; - in->amp = in->amp0 + (ts - in->ts_start) * in->damp; - } - ws->next_inter = i; - ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS; - *last = -1; - lcg_seek(&ws->dither_state, (uint32_t)ts - (uint32_t)ws->cur_ts); - if (ws->pink_need) { - uint64_t pink_ts_cur = (ws->cur_ts + (uint64_t)PINK_UNIT - 1) & ~(PINK_UNIT - 1); - uint64_t pink_ts_next = ts & ~(PINK_UNIT - 1); - int pos = ts & (PINK_UNIT - 1); - lcg_seek(&ws->pink_state, (uint32_t)(pink_ts_next - pink_ts_cur) * 2); - if (pos) { - pink_fill(ws); - ws->pink_pos = pos; - } else { - ws->pink_pos = PINK_UNIT; - } - } - ws->cur_ts = ts; -} - -static int wavesynth_parse_extradata(AVCodecContext *avc) -{ - struct wavesynth_context *ws = avc->priv_data; - struct ws_interval *in; - uint8_t *edata, *edata_end; - int32_t f1, f2, a1, a2; - uint32_t phi; - int64_t dphi1, dphi2, dt, cur_ts = -0x8000000000000000; - int i; - - if (avc->extradata_size < 4) - return AVERROR(EINVAL); - edata = avc->extradata; - edata_end = edata + avc->extradata_size; - ws->nb_inter = AV_RL32(edata); - edata += 4; - if (ws->nb_inter < 0 || (edata_end - edata) / 24 < ws->nb_inter) - return AVERROR(EINVAL); - ws->inter = av_calloc(ws->nb_inter, sizeof(*ws->inter)); - if (!ws->inter) - return AVERROR(ENOMEM); - for (i = 0; i < ws->nb_inter; i++) { - in = &ws->inter[i]; - if (edata_end - edata < 24) - return AVERROR(EINVAL); - in->ts_start = AV_RL64(edata + 0); - in->ts_end = AV_RL64(edata + 8); - in->type = AV_RL32(edata + 16); - in->channels = AV_RL32(edata + 20); - edata += 24; - if (in->ts_start < cur_ts || - in->ts_end <= in->ts_start || - (uint64_t)in->ts_end - in->ts_start > INT64_MAX - ) - return AVERROR(EINVAL); - cur_ts = in->ts_start; - dt = in->ts_end - in->ts_start; - switch (in->type) { - case WS_SINE: - if (edata_end - edata < 20 || avc->sample_rate <= 0) - return AVERROR(EINVAL); - f1 = AV_RL32(edata + 0); - f2 = AV_RL32(edata + 4); - a1 = AV_RL32(edata + 8); - a2 = AV_RL32(edata + 12); - phi = AV_RL32(edata + 16); - edata += 20; - dphi1 = frac64(f1, (int64_t)avc->sample_rate << 16); - dphi2 = frac64(f2, (int64_t)avc->sample_rate << 16); - in->dphi0 = dphi1; - in->ddphi = (int64_t)(dphi2 - (uint64_t)dphi1) / dt; - if (phi & 0x80000000) { - phi &= ~0x80000000; - if (phi >= i) - return AVERROR(EINVAL); - in->phi0 = phi_at(&ws->inter[phi], in->ts_start); - } else { - in->phi0 = (uint64_t)phi << 33; - } - break; - case WS_NOISE: - if (edata_end - edata < 8) - return AVERROR(EINVAL); - a1 = AV_RL32(edata + 0); - a2 = AV_RL32(edata + 4); - edata += 8; - break; - default: - return AVERROR(EINVAL); - } - in->amp0 = (uint64_t)a1 << 32; - in->damp = (int64_t)(((uint64_t)a2 << 32) - ((uint64_t)a1 << 32)) / dt; - } - if (edata != edata_end) - return AVERROR(EINVAL); - return 0; -} - -static av_cold int wavesynth_init(AVCodecContext *avc) -{ - struct wavesynth_context *ws = avc->priv_data; - int i, r; - - if (avc->ch_layout.nb_channels > WS_MAX_CHANNELS) { - av_log(avc, AV_LOG_ERROR, - "This implementation is limited to %d channels.\n", - WS_MAX_CHANNELS); - return AVERROR(EINVAL); - } - r = wavesynth_parse_extradata(avc); - if (r < 0) { - av_log(avc, AV_LOG_ERROR, "Invalid intervals definitions.\n"); - return r; - } - ws->sin = av_malloc(sizeof(*ws->sin) << SIN_BITS); - if (!ws->sin) - return AVERROR(ENOMEM); - for (i = 0; i < 1 << SIN_BITS; i++) - ws->sin[i] = floor(32767 * sin(2 * M_PI * i / (1 << SIN_BITS))); - ws->dither_state = MKTAG('D','I','T','H'); - for (i = 0; i < ws->nb_inter; i++) - ws->pink_need += ws->inter[i].type == WS_NOISE; - ws->pink_state = MKTAG('P','I','N','K'); - ws->pink_pos = PINK_UNIT; - wavesynth_seek(ws, 0); - avc->sample_fmt = AV_SAMPLE_FMT_S16; - return 0; -} - -static void wavesynth_synth_sample(struct wavesynth_context *ws, int64_t ts, - int32_t *channels) -{ - int32_t amp, *cv; - unsigned val; - struct ws_interval *in; - int i, *last, pink; - uint32_t c, all_ch = 0; - - i = ws->cur_inter; - last = &ws->cur_inter; - if (ws->pink_pos == PINK_UNIT) - pink_fill(ws); - pink = ws->pink_pool[ws->pink_pos++] >> 16; - while (i >= 0) { - in = &ws->inter[i]; - i = in->next; - if (ts >= in->ts_end) { - *last = i; - continue; - } - last = &in->next; - amp = in->amp >> 32; - in->amp += in->damp; - switch (in->type) { - case WS_SINE: - val = amp * (unsigned)ws->sin[in->phi >> (64 - SIN_BITS)]; - in->phi += in->dphi; - in->dphi += in->ddphi; - break; - case WS_NOISE: - val = amp * (unsigned)pink; - break; - default: - val = 0; - } - all_ch |= in->channels; - for (c = in->channels, cv = channels; c; c >>= 1, cv++) - if (c & 1) - *cv += (unsigned)val; - } - val = (int32_t)lcg_next(&ws->dither_state) >> 16; - for (c = all_ch, cv = channels; c; c >>= 1, cv++) - if (c & 1) - *cv += val; -} - -static void wavesynth_enter_intervals(struct wavesynth_context *ws, int64_t ts) -{ - int *last, i; - struct ws_interval *in; - - last = &ws->cur_inter; - for (i = ws->cur_inter; i >= 0; i = ws->inter[i].next) - last = &ws->inter[i].next; - for (i = ws->next_inter; i < ws->nb_inter; i++) { - in = &ws->inter[i]; - if (ts < in->ts_start) - break; - if (ts >= in->ts_end) - continue; - *last = i; - last = &in->next; - in->phi = in->phi0; - in->dphi = in->dphi0; - in->amp = in->amp0; - } - ws->next_inter = i; - ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS; - *last = -1; -} - -static int wavesynth_decode(AVCodecContext *avc, AVFrame *frame, - int *rgot_frame, AVPacket *packet) -{ - struct wavesynth_context *ws = avc->priv_data; - int64_t ts; - int duration; - int s, c, r; - int16_t *pcm; - int32_t channels[WS_MAX_CHANNELS]; - - *rgot_frame = 0; - if (packet->size != 12) - return AVERROR_INVALIDDATA; - ts = AV_RL64(packet->data); - if (ts != ws->cur_ts) - wavesynth_seek(ws, ts); - duration = AV_RL32(packet->data + 8); - if (duration <= 0) - return AVERROR(EINVAL); - frame->nb_samples = duration; - r = ff_get_buffer(avc, frame, 0); - if (r < 0) - return r; - pcm = (int16_t *)frame->data[0]; - for (s = 0; s < duration; s++, ts+=(uint64_t)1) { - memset(channels, 0, avc->ch_layout.nb_channels * sizeof(*channels)); - if (ts >= ws->next_ts) - wavesynth_enter_intervals(ws, ts); - wavesynth_synth_sample(ws, ts, channels); - for (c = 0; c < avc->ch_layout.nb_channels; c++) - *(pcm++) = channels[c] >> 16; - } - ws->cur_ts += (uint64_t)duration; - *rgot_frame = 1; - return packet->size; -} - -static av_cold int wavesynth_close(AVCodecContext *avc) -{ - struct wavesynth_context *ws = avc->priv_data; - - av_freep(&ws->sin); - av_freep(&ws->inter); - return 0; -} - -const FFCodec ff_ffwavesynth_decoder = { - .p.name = "wavesynth", - CODEC_LONG_NAME("Wave synthesis pseudo-codec"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_FFWAVESYNTH, - .priv_data_size = sizeof(struct wavesynth_context), - .init = wavesynth_init, - .close = wavesynth_close, - FF_CODEC_DECODE_CB(wavesynth_decode), - .p.capabilities = AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, -}; diff --git a/libavcodec/version_major.h b/libavcodec/version_major.h index 40db213499..b7af4518c9 100644 --- a/libavcodec/version_major.h +++ b/libavcodec/version_major.h @@ -41,6 +41,7 @@ #define FF_API_IDCT_NONE (LIBAVCODEC_VERSION_MAJOR < 61) #define FF_API_SVTAV1_OPTS (LIBAVCODEC_VERSION_MAJOR < 61) #define FF_API_AYUV_CODECID (LIBAVCODEC_VERSION_MAJOR < 61) +#define FF_API_FFWAVESYNTH_CODECID (LIBAVCODEC_VERSION_MAJOR < 61) #define FF_API_VT_OUTPUT_CALLBACK (LIBAVCODEC_VERSION_MAJOR < 61) #define FF_API_AVCODEC_CHROMA_POS (LIBAVCODEC_VERSION_MAJOR < 61) #define FF_API_VT_HWACCEL_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 61) -- 2.39.1