Commit 5f47c85e authored by Rostislav Pehlivanov's avatar Rostislav Pehlivanov

opus: add a native Opus encoder

This marks the first time anyone has written an Opus encoder without
using any libopus code. The aim of the encoder is to prove how far
the format can go by writing the craziest encoder for it.

Right now the encoder's basic, it only supports CBR encoding, however
internally every single feature the CELT layer has is implemented
(except the pitch pre-filter which needs to work well with the rest of
whatever gets implemented). Psychoacoustic and rate control systems are
under development.

The encoder takes in frames of 120 samples and depending on the value of
opus_delay the plan is to use the extra buffered frames as lookahead.
Right now the encoder will pick the nearest largest legal frame size and
won't use the lookahead, but that'll change once there's a
psychoacoustic system.

Even though its a pretty basic encoder its already outperforming
any other native encoder FFmpeg has by a huge amount.

The PVQ search algorithm is faster and more accurate than libopus's
algorithm so the encoder's performance is close to that of libopus
at zero complexity (libopus has more SIMD).
The algorithm might be ported to libopus or other codecs using PVQ in
the future.

The encoder still has a few minor bugs, like desyncs at ultra low
bitrates (below 9kbps with 20ms frames).
Signed-off-by: 's avatarRostislav Pehlivanov <atomnuker@gmail.com>
parent 07b78340
......@@ -2492,6 +2492,7 @@ nuv_decoder_select="idctdsp lzo"
on2avc_decoder_select="mdct"
opus_decoder_deps="swresample"
opus_decoder_select="mdct15"
opus_encoder_select="audio_frame_queue audiodsp mdct15"
png_decoder_select="zlib"
png_encoder_select="llvidencdsp zlib"
prores_decoder_select="blockdsp idctdsp"
......
......@@ -444,6 +444,7 @@ OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o
OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o
OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opus.o opus_celt.o opus_rc.o \
opus_pvq.o opus_silk.o opustab.o vorbis_data.o
OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus_rc.o opustab.o opus_pvq.o
OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o
OBJS-$(CONFIG_PAF_VIDEO_DECODER) += pafvideo.o
OBJS-$(CONFIG_PAM_DECODER) += pnmdec.o pnm.o
......
......@@ -449,7 +449,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(MPC8, mpc8);
REGISTER_ENCDEC (NELLYMOSER, nellymoser);
REGISTER_DECODER(ON2AVC, on2avc);
REGISTER_DECODER(OPUS, opus);
REGISTER_ENCDEC (OPUS, opus);
REGISTER_DECODER(PAF_AUDIO, paf_audio);
REGISTER_DECODER(QCELP, qcelp);
REGISTER_DECODER(QDM2, qdm2);
......
......@@ -61,14 +61,23 @@ enum CeltBlockSize {
typedef struct CeltBlock {
float energy[CELT_MAX_BANDS];
float lin_energy[CELT_MAX_BANDS];
float error_energy[CELT_MAX_BANDS];
float prev_energy[2][CELT_MAX_BANDS];
uint8_t collapse_masks[CELT_MAX_BANDS];
int band_bins[CELT_MAX_BANDS]; /* MDCT bins per band */
float *band_coeffs[CELT_MAX_BANDS];
/* buffer for mdct output + postfilter */
DECLARE_ALIGNED(32, float, buf)[2048];
DECLARE_ALIGNED(32, float, coeffs)[CELT_MAX_FRAME_SIZE];
/* Used by the encoder */
DECLARE_ALIGNED(32, float, overlap)[120];
DECLARE_ALIGNED(32, float, samples)[CELT_MAX_FRAME_SIZE];
/* postfilter parameters */
int pf_period_new;
float pf_gains_new[3];
......@@ -94,6 +103,12 @@ struct CeltFrame {
int end_band;
int coded_bands;
int transient;
int intra;
int pfilter;
int skip_band_floor;
int tf_select;
int alloc_trim;
int alloc_boost[CELT_MAX_BANDS];
int blocks; /* number of iMDCT blocks in the frame, depends on transient */
int blocksize; /* size of each block */
int silence; /* Frame is filled with silence */
......@@ -109,6 +124,7 @@ struct CeltFrame {
int framebits;
int remaining;
int remaining2;
int caps [CELT_MAX_BANDS];
int fine_bits [CELT_MAX_BANDS];
int fine_priority[CELT_MAX_BANDS];
int pulses [CELT_MAX_BANDS];
......
This diff is collapsed.
......@@ -32,4 +32,10 @@ uint32_t ff_celt_decode_band(CeltFrame *f, OpusRangeCoder *rc, const int band,
float *lowband, int duration, float *lowband_out, int level,
float gain, float *lowband_scratch, int fill);
/* Encodes a band using PVQ */
uint32_t ff_celt_encode_band(CeltFrame *f, OpusRangeCoder *rc, const int band,
float *X, float *Y, int N, int b, uint32_t blocks,
float *lowband, int duration, float *lowband_out, int level,
float gain, float *lowband_scratch, int fill);
#endif /* AVCODEC_OPUS_PVQ_H */
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment