Peter Ross: > --- > libavcodec/Makefile | 1 + > libavcodec/allcodecs.c | 1 + > libavcodec/codec_desc.c | 7 ++ > libavcodec/codec_id.h | 1 + > libavcodec/g728data.h | 70 +++++++++++++ > libavcodec/g728dec.c | 213 ++++++++++++++++++++++++++++++++++++++++ > libavcodec/utils.c | 1 + > 7 files changed, 294 insertions(+) > create mode 100644 libavcodec/g728data.h > create mode 100644 libavcodec/g728dec.c > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index a3ef11a258..6400d73115 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -394,6 +394,7 @@ OBJS-$(CONFIG_G723_1_DECODER) += g723_1dec.o > g723_1.o \ > acelp_vectors.o celp_filters.o > celp_math.o > OBJS-$(CONFIG_G723_1_ENCODER) += g723_1enc.o g723_1.o \ > acelp_vectors.o celp_filters.o > celp_math.o > +OBJS-$(CONFIG_G728_DECODER) += g728dec.o > OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_math.o > celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o > g729postfilter.o > OBJS-$(CONFIG_GDV_DECODER) += gdv.o > OBJS-$(CONFIG_GEM_DECODER) += gemdec.o > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index af2a2b36e4..0975de5103 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -475,6 +475,7 @@ extern const FFCodec ff_flac_decoder; > extern const FFCodec ff_ftr_decoder; > extern const FFCodec ff_g723_1_encoder; > extern const FFCodec ff_g723_1_decoder; > +extern const FFCodec ff_g728_decoder; > extern const FFCodec ff_g729_decoder; > extern const FFCodec ff_gsm_decoder; > extern const FFCodec ff_gsm_ms_decoder; > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c > index b734d07ded..d8bd30d0e1 100644 > --- a/libavcodec/codec_desc.c > +++ b/libavcodec/codec_desc.c > @@ -3466,6 +3466,13 @@ static const AVCodecDescriptor codec_descriptors[] = { > .long_name = NULL_IF_CONFIG_SMALL("LC3 (Low Complexity Communication > Codec)"), > .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, > }, > + { > + .id = AV_CODEC_ID_G728, > + .type = AVMEDIA_TYPE_AUDIO, > + .name = "g728", > + .long_name = NULL_IF_CONFIG_SMALL("G.728"), > + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, > + }, > > /* subtitle codecs */ > { > diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h > index 97b70c5bf5..ee02fe4261 100644 > --- a/libavcodec/codec_id.h > +++ b/libavcodec/codec_id.h > @@ -552,6 +552,7 @@ enum AVCodecID { > AV_CODEC_ID_OSQ, > AV_CODEC_ID_QOA, > AV_CODEC_ID_LC3, > + AV_CODEC_ID_G728, > > /* subtitle codecs */ > AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing > at the start of subtitle codecs. > diff --git a/libavcodec/g728data.h b/libavcodec/g728data.h > new file mode 100644 > index 0000000000..a2ddf5682d > --- /dev/null > +++ b/libavcodec/g728data.h > @@ -0,0 +1,70 @@ > +/* > + * G.728 decoder > + * > + * 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 > + */ > + > +#ifndef AVCODEC_G728DATA_H > +#define AVCODEC_G728DATA_H > + > +#include <stdint.h> > +#include "libavutil/macros.h" > + > +#define IDIM 5 /* Vector dimension (excitation block size) */ > +#define LPC 50 /* Synthesis filter order */ > +#define LPCLG 10 /* Log-gain predictor order */ > +#define NFRSZ 20 /* Frame size (adaptation cycle size in samples */ > +#define NONR 35 /* Number of non-recursive window samples for synthesis > filter */ > +#define NONRLG 20 /* Number of non-recursive window samples for log-gain > predictor */ > +#define NUPDATE 4 /* Predictor update period (in terms of vectors) */ > + > +#define NSBSZ (LPC + NONR + NFRSZ) > +#define NSBGSZ (LPCLG + NONRLG + NUPDATE) > + > +// Hybrid window for the synthesis filter > +static const uint16_t g728_wnr[NSBSZ] = { > + 1565, 3127, 4681, 6225, 7755, 9266, 10757, 12223, 13661, 15068, > + 16441, 17776, 19071, 20322, 21526, 22682, 23786, 24835, 25828, 26761, > + 27634, 28444, 29188, 29866, 30476, 31016, 31486, 31884, 32208, 32460, > + 32637, 32739, 32767, 32721, 32599, 32403, 32171, 31940, 31711, 31484, > + 31259, 31034, 30812, 30591, 30372, 30154, 29938, 29724, 29511, 29299, > + 29089, 28881, 28674, 28468, 28264, 28062, 27861, 27661, 27463, 27266, > + 27071, 26877, 26684, 26493, 26303, 26114, 25927, 25742, 25557, 25374, > + 25192, 25012, 24832, 24654, 24478, 24302, 24128, 23955, 23784, 23613, > + 23444, 23276, 23109, 22943, 22779, 22616, 22454, 22293, 22133, 21974, > + 21817, 21661, 21505, 21351, 21198, 21046, 20896, 20746, 20597, 20450, > + 20303, 20157, 20013, 19870, 19727 > +}; > + > +// Hybrid window for the log-gain predictor > +static const uint16_t g728_wnrg[NSBGSZ] = { > + 3026, 6025, 8973, 11845, 14615, 17261, 19759, 22088, 24228, 26162, > + 27872, 29344, 30565, 31525, 32216, 32631, 32767, 32625, 32203, 31506, > + 30540, 29461, 28420, 27416, 26448, 25514, 24613, 23743, 22905, 22096, > + 21315, 20562, 19836, 19135 > +}; > + > +// Values for bandwidth broadcasting > +static const uint16_t g728_facv[LPC] = { > + 16192, 16002, 15815, 15629, 15446, 15265, 15086, 14910, 14735, 14562, > + 14391, 14223, 14056, 13891, 13729, 13568, 13409, 13252, 13096, 12943, > + 12791, 12641, 12493, 12347, 12202, 12059, 11918, 11778, 11640, 11504, > + 11369, 11236, 11104, 10974, 10845, 10718, 10593, 10468, 10346, 10225, > + 10105, 9986, 9869, 9754, 9639, 9526, 9415, 9304, 9195, 9088 > +}; > + > +#endif /* AVCODEC_G728DATA_H */ > diff --git a/libavcodec/g728dec.c b/libavcodec/g728dec.c > new file mode 100644 > index 0000000000..ff861ff1c0 > --- /dev/null > +++ b/libavcodec/g728dec.c > @@ -0,0 +1,213 @@ > +/* > + * G.728 decoder > + * Copyright (c) 2025 Peter Ross > + * > + * 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 "avcodec.h" > +#include "celp_filters.h" > +#include "codec_internal.h" > +#include "decode.h" > +#include "get_bits.h" > +#include "g728data.h" > +#include "lpc_functions.h" > +#include "ra288.h" > +#include "libavutil/float_dsp.h" > +#include "libavutil/mem.h" > +#include "libavutil/mem_internal.h" > +#include "libavutil/opt.h" > +#include "libavutil/thread.h" > + > +#define MAX_BACKWARD_FILTER_ORDER LPC > +#define MAX_BACKWARD_FILTER_LEN NFRSZ > +#define MAX_BACKWARD_FILTER_NONREC NONR > +#define ATTEN 0.75f > +#include "g728_template.c" > + > +#define LPCW 10 /* Perceptual weighting filter order */ > +#define GOFF 32.0f /* Log-gain offset value */ > + > +static float g728_gq_db[8]; > +static float g728_y_db[128]; > +static float g728_wnr_r[FFALIGN(NSBSZ,16)]; > +static float g728_wnrg_r[FFALIGN(NSBGSZ, 16)]; > +static float g728_facv_f[FFALIGN(LPC, 16)]; > + > +static av_cold void g728_init_static_data(void) > +{ > + for(int i = 0; i < FF_ARRAY_ELEMS(amptable); i++) > + g728_gq_db[i] = 10.0f*log10f(amptable[i] * amptable[i]); > + > + for (int i = 0; i < FF_ARRAY_ELEMS(codetable); i++) { > + float cby[IDIM]; > + for (int j = 0; j < IDIM; j++) > + cby[j] = codetable[i][j] * (1.0f/(1<<11)); > + g728_y_db[i] = 10.0f*log10f(avpriv_scalarproduct_float_c(cby, cby, > IDIM) / IDIM); > + } > + > + for (int i = 0; i < NSBSZ; i++) > + g728_wnr_r[i] = g728_wnr[NSBSZ - 1 - i] * (1.0f/(1<<15)); > + for (int i = 0; i < NSBGSZ; i++) > + g728_wnrg_r[i] = g728_wnrg[NSBGSZ - 1 - i] * (1.0f/(1<<15)); > + for (int i = 0; i < LPC; i++) > + g728_facv_f[i] = g728_facv[i] * (1.0f/(1<<14)); > +} > + > +typedef struct { > + AVFloatDSPContext *fdsp; > + int valid; > + float a[LPC]; > + DECLARE_ALIGNED(32, float, sb)[NSBSZ]; > + DECLARE_ALIGNED(32, float, sbg)[NSBGSZ]; > + DECLARE_ALIGNED(32, float, gp)[FFALIGN(LPCLG, 16)]; > + DECLARE_ALIGNED(32, float, atmp)[FFALIGN(LPC, 16)]; > + float rexp[LPC + 1]; > + float rexpg[LPCLG + 1]; > + float r[LPC + 1]; > + float alpha; > +} G728Context; > + > +static av_cold int g728_decode_init(AVCodecContext *avctx) > +{ > + static AVOnce init_static_once = AV_ONCE_INIT; > + G728Context *s = avctx->priv_data; > + > + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); > + if (!s->fdsp) > + return AVERROR(ENOMEM); > + > + s->gp[0] = -1.0f; > + for (int i = 0; i < NUPDATE; i++) > + s->sbg[NSBGSZ - 1 -i] = -GOFF; > + > + avctx->sample_fmt = AV_SAMPLE_FMT_FLT; > + > + ff_thread_once(&init_static_once, g728_init_static_data); > + return 0; > +} > + > +static av_cold int g728_decode_close(AVCodecContext *avctx) > +{ > + G728Context *s = avctx->priv_data; > + av_freep(&s->fdsp); > + return 0; > +} > + > +static int hybrid_window(AVFloatDSPContext *fdsp, > + int order, int n, int non_rec, float *out, > + const float *hist, float *out2, const float *window) > +{ > + do_hybrid_window(fdsp->vector_fmul, order, n, non_rec, out, hist, out2, > window); > + return out[order] != 0.0f; > +} > + > +static void decode_frame(G728Context *s, GetBitContext *gb, float *dst) > +{ > + float *gstate = s->sbg + NSBGSZ - 2; > + > + for (int idx = 0; idx < NUPDATE; idx++) { > + DECLARE_ALIGNED(32, float, et)[IDIM]; > + float *statelpc = s->sb + NSBSZ - NFRSZ + idx*IDIM; > + float gain, gain_db; > + int is, ig; > + > + gain_db = 0.0f; > + for (int i = 0; i < LPCLG; i++) > + gain_db -= s->gp[i] * gstate[-i]; > + gain_db = av_clipf(gain_db, -GOFF, 28.0f); > + > + is = get_bits(gb, 7); // shape index > + ig = get_bits(gb, 3); // gain index > + > + gain = powf(10.0f, (gain_db + GOFF) * .05f) * amptable[ig] * > (1.0f/(1<<11)); > + for (int i = 0; i < IDIM; i++) > + et[i] = codetable[is][i] * gain; > + > + ff_celp_lp_synthesis_filterf(statelpc, s->a, et, IDIM, LPC); > + > + for (int i = 0; i < IDIM; i++) { > + statelpc[i] = av_clipf(statelpc[i], -4095.0f, 4095.0f); > + dst[idx*IDIM + i] = statelpc[i] * (1.0f/(1<<12)); > + } > + > + gstate++; > + *gstate = FFMAX(-GOFF, g728_gq_db[ig] + g728_y_db[is] + gain_db); > + > + if (idx == 0) { > + DECLARE_ALIGNED(32, float, gptmp)[FFALIGN(LPCLG, 16)]; > + if (s->valid && (s->valid = !compute_lpc_coefs(s->r + 1, LPCW, > LPC, s->atmp, 0, 0, 1, &s->alpha))) { > + s->fdsp->vector_fmul(s->atmp, s->atmp, g728_facv_f, > FFALIGN(LPC, 16)); > + } > + if (hybrid_window(s->fdsp, LPCLG, NUPDATE, NONRLG, s->r, s->sbg, > s->rexpg, g728_wnrg_r) && > + !compute_lpc_coefs(s->r, 0, LPCLG, gptmp, 0, 0, 1, > &s->alpha)) { > + s->fdsp->vector_fmul(s->gp, gptmp, gain_bw_tab, > FFALIGN(LPCLG, 16)); > + } > + memmove(s->sbg, s->sbg + NUPDATE, sizeof(float)*(LPCLG + > NONRLG)); > + gstate = s->sbg + NSBGSZ - 1 - NUPDATE; > + } else if (idx == 1) { > + if (s->valid) > + memcpy(s->a, s->atmp, sizeof(float)*LPC); > + } > + } > + > + s->valid = 0; > + if (hybrid_window(s->fdsp, LPC, NFRSZ, NONR, s->r, s->sb, s->rexp, > g728_wnr_r)) { > + s->valid = !compute_lpc_coefs(s->r, 0, LPCW, s->atmp, 0, 0, 1, > &s->alpha); > + } > + > + memmove(s->sb, s->sb + NFRSZ, sizeof(float)*(LPC + NONR)); > +} > + > +static int g728_decode_frame(AVCodecContext *avctx, AVFrame *frame, > + int *got_frame_ptr, AVPacket *avpkt) > +{ > + G728Context *s = avctx->priv_data; > + GetBitContext gb; > + int ret; > + > + if (avpkt->size < 5) > + return AVERROR_INVALIDDATA; > + > + if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) > + return ret; > + > + frame->nb_samples = 20; > + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) > + return ret; > + > + decode_frame(s, &gb, (float *)frame->data[0]); > + > + *got_frame_ptr = 1; > + > + return 5;
Won't decoding in 5 byte blocks incur a lot of overhead? > +} > + > +const FFCodec ff_g728_decoder = { > + .p.name = "g728", > + CODEC_LONG_NAME("G.728)"), > + .p.type = AVMEDIA_TYPE_AUDIO, > + .p.id = AV_CODEC_ID_G728, > + .priv_data_size = sizeof(G728Context), > + .init = g728_decode_init, > + .close = g728_decode_close, > + FF_CODEC_DECODE_CB(g728_decode_frame), > + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | > + AV_CODEC_CAP_DR1, > + .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, > + AV_SAMPLE_FMT_NONE }, > +}; > diff --git a/libavcodec/utils.c b/libavcodec/utils.c > index dd846b4ae9..58b29c4c9d 100644 > --- a/libavcodec/utils.c > +++ b/libavcodec/utils.c > @@ -553,6 +553,7 @@ int av_get_bits_per_sample(enum AVCodecID codec_id) > case AV_CODEC_ID_DFPWM: > return 1; > case AV_CODEC_ID_ADPCM_SBPRO_2: > + case AV_CODEC_ID_G728: > return 2; > case AV_CODEC_ID_ADPCM_SBPRO_3: > return 3; > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".