mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: asha-codec-g722: Drop the dependency on FFmpeg
We use the G722 encoder from Android itself and drop the dependency on FFmpeg/libav.
This commit is contained in:
parent
27e0338f24
commit
dbed1bdf3d
4 changed files with 547 additions and 120 deletions
|
|
@ -6,14 +6,9 @@
|
|||
#include <spa/utils/dict.h>
|
||||
#include <spa/debug/log.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/channel_layout.h>
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/samplefmt.h>
|
||||
|
||||
#include "rtp.h"
|
||||
#include "media-codecs.h"
|
||||
#include "g722/g722_enc_dec.h"
|
||||
|
||||
#define ASHA_HEADER_SZ 1 /* 1 byte sequence number */
|
||||
#define ASHA_ENCODED_PKT_SZ 160
|
||||
|
|
@ -21,11 +16,7 @@
|
|||
static struct spa_log *spalog;
|
||||
|
||||
struct impl {
|
||||
const AVCodec *avcodec;
|
||||
AVCodecContext *ctx;
|
||||
AVFrame *frame;
|
||||
AVPacket *pkt;
|
||||
|
||||
g722_encode_state_t encode;
|
||||
unsigned int codesize;
|
||||
};
|
||||
|
||||
|
|
@ -96,14 +87,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
|
||||
static void codec_deinit(void *data)
|
||||
{
|
||||
struct impl *this = data;
|
||||
|
||||
if (this->frame)
|
||||
av_frame_free(&this->frame);
|
||||
if (this->pkt)
|
||||
av_packet_free(&this->pkt);
|
||||
if (this->ctx)
|
||||
avcodec_free_context(&this->ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
||||
|
|
@ -111,64 +95,11 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
|||
void *props, size_t mtu)
|
||||
{
|
||||
struct impl *this;
|
||||
const AVCodec *avcodec;
|
||||
AVCodecContext *c = NULL;
|
||||
AVFrame *frame = NULL;
|
||||
AVPacket *pkt = NULL;
|
||||
|
||||
if ((this = calloc(1, sizeof(struct impl))) == NULL)
|
||||
goto error;
|
||||
return NULL;
|
||||
|
||||
avcodec = avcodec_find_encoder(AV_CODEC_ID_ADPCM_G722);
|
||||
if (!avcodec) {
|
||||
spa_log_error(spalog, "Codec not found");
|
||||
goto error;
|
||||
}
|
||||
|
||||
c = avcodec_alloc_context3(avcodec);
|
||||
if (!c) {
|
||||
spa_log_error(spalog, "Codec context allocation failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* https://source.android.com/docs/core/connect/bluetooth/asha#audio-packet-format-and-timing */
|
||||
c->bit_rate = 64000;
|
||||
c->sample_rate = 16000;
|
||||
c->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
av_channel_layout_copy(&c->ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO);
|
||||
|
||||
spa_log_info(spalog, "Opening codec, format: %d, rate: %d, layout: %d", c->sample_fmt, c->sample_rate, c->ch_layout.nb_channels);
|
||||
|
||||
if (avcodec_open2(c, avcodec, NULL) < 0) {
|
||||
spa_log_error(spalog, "Could not open codec");
|
||||
goto error;
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
spa_log_error(spalog, "Could not allocate frame");
|
||||
goto error;
|
||||
}
|
||||
|
||||
frame->nb_samples = c->frame_size;
|
||||
frame->format = c->sample_fmt;
|
||||
if (av_channel_layout_copy (&frame->ch_layout, &c->ch_layout)) {
|
||||
spa_log_error(spalog, "Failed to copy channel layout");
|
||||
goto error;
|
||||
}
|
||||
|
||||
spa_log_info(spalog, "Frame info, samples: %d, format: %d, layout: %d", frame->nb_samples, frame->format, frame->ch_layout.nb_channels);
|
||||
|
||||
if (av_frame_get_buffer(frame, 0)) {
|
||||
spa_log_error(spalog, "Failed to allocate buffer for frame");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pkt = av_packet_alloc();
|
||||
if (!pkt) {
|
||||
spa_log_error(spalog, "Could not allocate packet");
|
||||
goto error;
|
||||
}
|
||||
g722_encode_init(&this->encode, 64000, G722_PACKED);
|
||||
|
||||
/*
|
||||
* G722 has a compression ratio of 4. Considering 160 bytes of encoded
|
||||
|
|
@ -176,22 +107,9 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
|
|||
*/
|
||||
this->codesize = ASHA_ENCODED_PKT_SZ * 4;
|
||||
|
||||
this->avcodec = avcodec;
|
||||
this->ctx = c;
|
||||
this->frame = frame;
|
||||
this->pkt = pkt;
|
||||
|
||||
spa_log_debug(spalog, "Codec initialized");
|
||||
|
||||
return this;
|
||||
|
||||
error:
|
||||
if (frame)
|
||||
av_frame_free(&frame);
|
||||
if (c)
|
||||
avcodec_free_context(&c);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int codec_encode(void *data,
|
||||
|
|
@ -200,8 +118,6 @@ static int codec_encode(void *data,
|
|||
size_t *dst_out, int *need_flush)
|
||||
{
|
||||
struct impl *this = data;
|
||||
AVFrame *frame = this->frame;
|
||||
AVPacket *pkt = this->pkt;
|
||||
size_t src_sz;
|
||||
int ret;
|
||||
|
||||
|
|
@ -209,45 +125,21 @@ static int codec_encode(void *data,
|
|||
spa_log_trace(spalog, "Insufficient bytes for encoding, %zd", src_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dst_size < (ASHA_HEADER_SZ + ASHA_ENCODED_PKT_SZ)) {
|
||||
spa_log_trace(spalog, "No space for encoded output, %zd", dst_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spa_log_trace(spalog, "%zd bytes to encode", src_size);
|
||||
|
||||
ret = av_frame_make_writable(this->frame);
|
||||
if (ret < 0) {
|
||||
spa_log_error(spalog, "Failed to make frame writable");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
src_sz = (src_size > this->codesize) ? this->codesize : src_size;
|
||||
frame->data[0] = (uint8_t *)src;
|
||||
frame->linesize[0] = src_sz;
|
||||
|
||||
spa_log_trace(spalog, "Encoding %zd bytes", src_sz);
|
||||
|
||||
ret = avcodec_send_frame(this->ctx, frame);
|
||||
ret = g722_encode(&this->encode, dst, src, src_sz / 2 /* S16LE */);
|
||||
if (ret < 0) {
|
||||
spa_log_error(spalog, "Failed to send frame: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = avcodec_receive_packet(this->ctx, pkt);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
||||
spa_log_warn(spalog, "Receive packet EOF/EAGAIN: %d", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
spa_log_error(spalog, "Receive packet error: %d", ret);
|
||||
spa_log_error(spalog, "encode error: %d", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(dst, pkt->data, pkt->size);
|
||||
|
||||
*dst_out = pkt->size;
|
||||
*dst_out = ret;
|
||||
*need_flush = NEED_FLUSH_ALL;
|
||||
|
||||
return src_sz;
|
||||
|
|
|
|||
148
spa/plugins/bluez5/g722/g722_enc_dec.h
Normal file
148
spa/plugins/bluez5/g722/g722_enc_dec.h
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g722.h - The ITU G.722 codec.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2005 Steve Underwood
|
||||
*
|
||||
* Despite my general liking of the GPL, I place my own contributions
|
||||
* to this code in the public domain for the benefit of all mankind -
|
||||
* even the slimy ones who might try to proprietize my work and use it
|
||||
* to my detriment.
|
||||
*
|
||||
* Based on a single channel G.722 codec which is:
|
||||
*
|
||||
***** Copyright (c) CMU 1993 *****
|
||||
* Computer Science, Speech Group
|
||||
* Chengxiang Lu and Alex Hauptmann
|
||||
*
|
||||
* $Id: g722.h 48959 2006-12-25 06:42:15Z rizzo $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#if !defined(_G722_H_)
|
||||
#define _G722_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*! \page g722_page G.722 encoding and decoding
|
||||
\section g722_page_sec_1 What does it do?
|
||||
The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
|
||||
specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
|
||||
|
||||
To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
|
||||
support an option for the linear audio to be an 8k samples/second stream. In this mode the
|
||||
codec is considerably faster, and still fully compatible with wideband terminals using G.722.
|
||||
|
||||
\section g722_page_sec_2 How does it work?
|
||||
???.
|
||||
*/
|
||||
|
||||
/* Format DAC12 is added to decode directly into samples suitable for
|
||||
a 12-bit DAC using offset binary representation. */
|
||||
|
||||
enum {
|
||||
G722_SAMPLE_RATE_8000 = 0x0001,
|
||||
G722_PACKED = 0x0002,
|
||||
G722_FORMAT_DAC12 = 0x0004,
|
||||
};
|
||||
|
||||
#ifdef BUILD_FEATURE_DAC
|
||||
#define NLDECOMPRESS_APPLY_GAIN(s, g) (((s) * (int32_t)(g)) >> 16)
|
||||
// Equivalent to shift 16, add 0x8000, shift 4
|
||||
#define NLDECOMPRESS_APPLY_GAIN_CONVERTED_DAC(s, g) \
|
||||
(uint16_t)((uint16_t)(((s) * (int32_t)(g)) >> 20) + 0x800)
|
||||
#else
|
||||
#define NLDECOMPRESS_APPLY_GAIN(s, g) (((int32_t)(s) * (int32_t)(g)) >> 16)
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_FEATURE_DAC
|
||||
#define NLDECOMPRESS_PREPROCESS_PCM_SAMPLE_WITH_GAIN(s, g) \
|
||||
NLDECOMPRESS_APPLY_GAIN_CONVERTED_DAC((s), (g))
|
||||
#define NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN(s, g) ((int16_t)NLDECOMPRESS_APPLY_GAIN((s), (g)))
|
||||
#else
|
||||
#define NLDECOMPRESS_PREPROCESS_PCM_SAMPLE_WITH_GAIN NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN
|
||||
#define NLDECOMPRESS_PREPROCESS_SAMPLE_WITH_GAIN(s, g) \
|
||||
((int16_t)(NLDECOMPRESS_APPLY_GAIN((s), (g))))
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int s;
|
||||
int sp;
|
||||
int sz;
|
||||
int r[3];
|
||||
int a[3];
|
||||
int ap[3];
|
||||
int p[3];
|
||||
int d[7];
|
||||
int b[7];
|
||||
int bp[7];
|
||||
int nb;
|
||||
int det;
|
||||
} g722_band_t;
|
||||
|
||||
typedef struct {
|
||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters disabled. */
|
||||
int itu_test_mode;
|
||||
/*! TRUE if the G.722 data is packed */
|
||||
int packed;
|
||||
/*! TRUE if encode from 8k samples/second */
|
||||
int eight_k;
|
||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||
int bits_per_sample;
|
||||
|
||||
/*! Signal history for the QMF */
|
||||
int x[24];
|
||||
|
||||
g722_band_t band[2];
|
||||
|
||||
unsigned int in_buffer;
|
||||
int in_bits;
|
||||
unsigned int out_buffer;
|
||||
int out_bits;
|
||||
} g722_encode_state_t;
|
||||
|
||||
typedef struct {
|
||||
/*! TRUE if the operating in the special ITU test mode, with the band split filters disabled. */
|
||||
int itu_test_mode;
|
||||
/*! TRUE if the G.722 data is packed */
|
||||
int packed;
|
||||
/*! TRUE if decode to 8k samples/second */
|
||||
int eight_k;
|
||||
/*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
|
||||
int bits_per_sample;
|
||||
/*! TRUE if offset binary for a 12-bit DAC */
|
||||
int dac_pcm;
|
||||
|
||||
/*! Signal history for the QMF */
|
||||
int x[24];
|
||||
|
||||
g722_band_t band[2];
|
||||
|
||||
unsigned int in_buffer;
|
||||
int in_bits;
|
||||
unsigned int out_buffer;
|
||||
int out_bits;
|
||||
} g722_decode_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, unsigned int rate, int options);
|
||||
int g722_encode_release(g722_encode_state_t *s);
|
||||
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
|
||||
|
||||
g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, unsigned int rate, int options);
|
||||
int g722_decode_release(g722_decode_state_t *s);
|
||||
uint32_t g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len,
|
||||
uint16_t aGain);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
387
spa/plugins/bluez5/g722/g722_encode.c
Normal file
387
spa/plugins/bluez5/g722/g722_encode.c
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* SpanDSP - a series of DSP components for telephony
|
||||
*
|
||||
* g722_encode.c - The ITU G.722 codec, encode part.
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2005 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Despite my general liking of the GPL, I place my own contributions
|
||||
* to this code in the public domain for the benefit of all mankind -
|
||||
* even the slimy ones who might try to proprietize my work and use it
|
||||
* to my detriment.
|
||||
*
|
||||
* Based on a single channel 64kbps only G.722 codec which is:
|
||||
*
|
||||
***** Copyright (c) CMU 1993 *****
|
||||
* Computer Science, Speech Group
|
||||
* Chengxiang Lu and Alex Hauptmann
|
||||
*
|
||||
* $Id: g722_encode.c,v 1.14 2006/07/07 16:37:49 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "g722_enc_dec.h"
|
||||
|
||||
#if !defined(FALSE)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#if !defined(TRUE)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
#define PACKED_OUTPUT (0)
|
||||
#define BITS_PER_SAMPLE (8)
|
||||
|
||||
#ifndef BUILD_FEATURE_G722_USE_INTRINSIC_SAT
|
||||
static __inline int16_t saturate(int32_t amp) {
|
||||
int16_t amp16;
|
||||
|
||||
/* Hopefully this is optimised for the common case - not clipping */
|
||||
amp16 = (int16_t)amp;
|
||||
if (amp == amp16) {
|
||||
return amp16;
|
||||
}
|
||||
if (amp > 0x7FFF) {
|
||||
return 0x7FFF;
|
||||
}
|
||||
return 0x8000;
|
||||
}
|
||||
#else
|
||||
static __inline int16_t saturate(int32_t val) {
|
||||
register int32_t res;
|
||||
__asm volatile("SSAT %0, #16, %1\n\t" : "=r"(res) : "r"(val) :);
|
||||
return (int16_t)res;
|
||||
}
|
||||
#endif
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void block4(g722_band_t *band, int d) {
|
||||
int wd1;
|
||||
int wd2;
|
||||
int wd3;
|
||||
int i;
|
||||
int sg[7];
|
||||
int ap1, ap2;
|
||||
int sg0, sgi;
|
||||
int sz;
|
||||
|
||||
/* Block 4, RECONS */
|
||||
band->d[0] = d;
|
||||
band->r[0] = saturate(band->s + d);
|
||||
|
||||
/* Block 4, PARREC */
|
||||
band->p[0] = saturate(band->sz + d);
|
||||
|
||||
/* Block 4, UPPOL2 */
|
||||
for (i = 0; i < 3; i++) {
|
||||
sg[i] = band->p[i] >> 15;
|
||||
}
|
||||
wd1 = saturate(band->a[1] << 2);
|
||||
|
||||
wd2 = (sg[0] == sg[1]) ? -wd1 : wd1;
|
||||
if (wd2 > 32767) {
|
||||
wd2 = 32767;
|
||||
}
|
||||
|
||||
ap2 = (wd2 >> 7) + ((sg[0] == sg[2]) ? 128 : -128);
|
||||
ap2 += (band->a[2] * 32512) >> 15;
|
||||
if (ap2 > 12288) {
|
||||
ap2 = 12288;
|
||||
} else if (ap2 < -12288) {
|
||||
ap2 = -12288;
|
||||
}
|
||||
band->ap[2] = ap2;
|
||||
|
||||
/* Block 4, UPPOL1 */
|
||||
sg[0] = band->p[0] >> 15;
|
||||
sg[1] = band->p[1] >> 15;
|
||||
wd1 = (sg[0] == sg[1]) ? 192 : -192;
|
||||
wd2 = (band->a[1] * 32640) >> 15;
|
||||
|
||||
ap1 = saturate(wd1 + wd2);
|
||||
wd3 = saturate(15360 - band->ap[2]);
|
||||
if (ap1 > wd3) {
|
||||
ap1 = wd3;
|
||||
} else if (ap1 < -wd3) {
|
||||
ap1 = -wd3;
|
||||
}
|
||||
band->ap[1] = ap1;
|
||||
|
||||
/* Block 4, UPZERO */
|
||||
/* Block 4, FILTEZ */
|
||||
wd1 = (d == 0) ? 0 : 128;
|
||||
|
||||
sg0 = sg[0] = d >> 15;
|
||||
for (i = 1; i < 7; i++) {
|
||||
sgi = band->d[i] >> 15;
|
||||
wd2 = (sgi == sg0) ? wd1 : -wd1;
|
||||
wd3 = (band->b[i] * 32640) >> 15;
|
||||
band->bp[i] = saturate(wd2 + wd3);
|
||||
}
|
||||
|
||||
/* Block 4, DELAYA */
|
||||
sz = 0;
|
||||
for (i = 6; i > 0; i--) {
|
||||
int bi;
|
||||
|
||||
band->d[i] = band->d[i - 1];
|
||||
bi = band->b[i] = band->bp[i];
|
||||
wd1 = saturate(band->d[i] + band->d[i]);
|
||||
sz += (bi * wd1) >> 15;
|
||||
}
|
||||
band->sz = sz;
|
||||
|
||||
for (i = 2; i > 0; i--) {
|
||||
band->r[i] = band->r[i - 1];
|
||||
band->p[i] = band->p[i - 1];
|
||||
band->a[i] = band->ap[i];
|
||||
}
|
||||
|
||||
/* Block 4, FILTEP */
|
||||
wd1 = saturate(band->r[1] + band->r[1]);
|
||||
wd1 = (band->a[1] * wd1) >> 15;
|
||||
wd2 = saturate(band->r[2] + band->r[2]);
|
||||
wd2 = (band->a[2] * wd2) >> 15;
|
||||
band->sp = saturate(wd1 + wd2);
|
||||
|
||||
/* Block 4, PREDIC */
|
||||
band->s = saturate(band->sp + band->sz);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, unsigned int rate, int options) {
|
||||
if (s == NULL) {
|
||||
#ifdef G722_SUPPORT_MALLOC
|
||||
if ((s = (g722_encode_state_t *)malloc(sizeof(*s))) == NULL)
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
memset(s, 0, sizeof(*s));
|
||||
if (rate == 48000) {
|
||||
s->bits_per_sample = 6;
|
||||
} else if (rate == 56000) {
|
||||
s->bits_per_sample = 7;
|
||||
} else {
|
||||
s->bits_per_sample = 8;
|
||||
}
|
||||
s->band[0].det = 32;
|
||||
s->band[1].det = 8;
|
||||
return s;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
int g722_encode_release(g722_encode_state_t *s) {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
/* WebRtc, tlegrand:
|
||||
* Only define the following if bit-exactness with reference implementation
|
||||
* is needed. Will only have any effect if input signal is saturated.
|
||||
*/
|
||||
// #define RUN_LIKE_REFERENCE_G722
|
||||
#ifdef RUN_LIKE_REFERENCE_G722
|
||||
int16_t limitValues(int16_t rl) {
|
||||
int16_t yl;
|
||||
|
||||
yl = (rl > 16383) ? 16383 : ((rl < -16384) ? -16384 : rl);
|
||||
|
||||
return yl;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
#endif
|
||||
|
||||
static int16_t q6[32] = {0, 35, 72, 110, 150, 190, 233, 276, 323, 370, 422,
|
||||
473, 530, 587, 650, 714, 786, 858, 940, 1023, 1121, 1219,
|
||||
1339, 1458, 1612, 1765, 1980, 2195, 2557, 2919, 0, 0};
|
||||
static int16_t iln[32] = {0, 63, 62, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
|
||||
18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 0};
|
||||
static int16_t ilp[32] = {0, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47,
|
||||
46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 0};
|
||||
static int16_t wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042};
|
||||
static int16_t rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0};
|
||||
static int16_t ilb[32] = {2048, 2093, 2139, 2186, 2233, 2282, 2332, 2383, 2435, 2489, 2543,
|
||||
2599, 2656, 2714, 2774, 2834, 2896, 2960, 3025, 3091, 3158, 3228,
|
||||
3298, 3371, 3444, 3520, 3597, 3676, 3756, 3838, 3922, 4008};
|
||||
static int16_t qm4[16] = {0, -20456, -12896, -8968, -6288, -4240, -2584, -1200,
|
||||
20456, 12896, 8968, 6288, 4240, 2584, 1200, 0};
|
||||
static int16_t qm2[4] = {-7408, -1616, 7408, 1616};
|
||||
static int16_t qmf_coeffs[12] = {
|
||||
3, -11, 12, 32, -210, 951, 3876, -805, 362, -156, 53, -11,
|
||||
};
|
||||
static int16_t ihn[3] = {0, 1, 0};
|
||||
static int16_t ihp[3] = {0, 3, 2};
|
||||
static int16_t wh[3] = {0, -214, 798};
|
||||
static int16_t rh2[4] = {2, 1, 2, 1};
|
||||
|
||||
int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len) {
|
||||
int dlow;
|
||||
int dhigh;
|
||||
int el;
|
||||
int wd;
|
||||
int wd1;
|
||||
int ril;
|
||||
int wd2;
|
||||
int il4;
|
||||
int ih2;
|
||||
int wd3;
|
||||
int eh;
|
||||
int mih;
|
||||
int i;
|
||||
int j;
|
||||
/* Low and high band PCM from the QMF */
|
||||
int xlow;
|
||||
int xhigh;
|
||||
int g722_bytes;
|
||||
/* Even and odd tap accumulators */
|
||||
int sumeven;
|
||||
int sumodd;
|
||||
int ihigh;
|
||||
int ilow;
|
||||
int code;
|
||||
|
||||
g722_bytes = 0;
|
||||
xhigh = 0;
|
||||
for (j = 0; j < len;) {
|
||||
if (s->itu_test_mode) {
|
||||
xlow = xhigh = amp[j++] >> 1;
|
||||
} else {
|
||||
{
|
||||
/* Apply the transmit QMF */
|
||||
/* Shuffle the buffer down */
|
||||
for (i = 0; i < 22; i++) {
|
||||
s->x[i] = s->x[i + 2];
|
||||
}
|
||||
// TODO: if len is odd, then this can be a buffer overrun
|
||||
s->x[22] = amp[j++];
|
||||
s->x[23] = amp[j++];
|
||||
|
||||
/* Discard every other QMF output */
|
||||
sumeven = 0;
|
||||
sumodd = 0;
|
||||
for (i = 0; i < 12; i++) {
|
||||
sumodd += s->x[2 * i] * qmf_coeffs[i];
|
||||
sumeven += s->x[2 * i + 1] * qmf_coeffs[11 - i];
|
||||
}
|
||||
/* We shift by 12 to allow for the QMF filters (DC gain = 4096), plus 1
|
||||
to allow for us summing two filters, plus 1 to allow for the 15 bit
|
||||
input to the G.722 algorithm. */
|
||||
xlow = (sumeven + sumodd) >> 14;
|
||||
xhigh = (sumeven - sumodd) >> 14;
|
||||
|
||||
#ifdef RUN_LIKE_REFERENCE_G722
|
||||
/* The following lines are only used to verify bit-exactness
|
||||
* with reference implementation of G.722. Higher precision
|
||||
* is achieved without limiting the values.
|
||||
*/
|
||||
xlow = limitValues(xlow);
|
||||
xhigh = limitValues(xhigh);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Block 1L, SUBTRA */
|
||||
el = saturate(xlow - s->band[0].s);
|
||||
|
||||
/* Block 1L, QUANTL */
|
||||
wd = (el >= 0) ? el : -(el + 1);
|
||||
|
||||
for (i = 1; i < 30; i++) {
|
||||
wd1 = (q6[i] * s->band[0].det) >> 12;
|
||||
if (wd < wd1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ilow = (el < 0) ? iln[i] : ilp[i];
|
||||
|
||||
/* Block 2L, INVQAL */
|
||||
ril = ilow >> 2;
|
||||
wd2 = qm4[ril];
|
||||
dlow = (s->band[0].det * wd2) >> 15;
|
||||
|
||||
/* Block 3L, LOGSCL */
|
||||
il4 = rl42[ril];
|
||||
wd = (s->band[0].nb * 127) >> 7;
|
||||
s->band[0].nb = wd + wl[il4];
|
||||
if (s->band[0].nb < 0) {
|
||||
s->band[0].nb = 0;
|
||||
} else if (s->band[0].nb > 18432) {
|
||||
s->band[0].nb = 18432;
|
||||
}
|
||||
|
||||
/* Block 3L, SCALEL */
|
||||
wd1 = (s->band[0].nb >> 6) & 31;
|
||||
wd2 = 8 - (s->band[0].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[0].det = wd3 << 2;
|
||||
|
||||
block4(&s->band[0], dlow);
|
||||
{
|
||||
int nb;
|
||||
|
||||
/* Block 1H, SUBTRA */
|
||||
eh = saturate(xhigh - s->band[1].s);
|
||||
|
||||
/* Block 1H, QUANTH */
|
||||
wd = (eh >= 0) ? eh : -(eh + 1);
|
||||
wd1 = (564 * s->band[1].det) >> 12;
|
||||
mih = (wd >= wd1) ? 2 : 1;
|
||||
ihigh = (eh < 0) ? ihn[mih] : ihp[mih];
|
||||
|
||||
/* Block 2H, INVQAH */
|
||||
wd2 = qm2[ihigh];
|
||||
dhigh = (s->band[1].det * wd2) >> 15;
|
||||
|
||||
/* Block 3H, LOGSCH */
|
||||
ih2 = rh2[ihigh];
|
||||
wd = (s->band[1].nb * 127) >> 7;
|
||||
|
||||
nb = wd + wh[ih2];
|
||||
if (nb < 0) {
|
||||
nb = 0;
|
||||
} else if (nb > 22528) {
|
||||
nb = 22528;
|
||||
}
|
||||
s->band[1].nb = nb;
|
||||
|
||||
/* Block 3H, SCALEH */
|
||||
wd1 = (s->band[1].nb >> 6) & 31;
|
||||
wd2 = 10 - (s->band[1].nb >> 11);
|
||||
wd3 = (wd2 < 0) ? (ilb[wd1] << -wd2) : (ilb[wd1] >> wd2);
|
||||
s->band[1].det = wd3 << 2;
|
||||
|
||||
block4(&s->band[1], dhigh);
|
||||
#if BITS_PER_SAMPLE == 8
|
||||
code = ((ihigh << 6) | ilow);
|
||||
#elif BITS_PER_SAMPLE == 7
|
||||
code = ((ihigh << 6) | ilow) >> 1;
|
||||
#elif BITS_PER_SAMPLE == 6
|
||||
code = ((ihigh << 6) | ilow) >> 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PACKED_OUTPUT == 1
|
||||
/* Pack the code bits */
|
||||
s->out_buffer |= (code << s->out_bits);
|
||||
s->out_bits += s->bits_per_sample;
|
||||
if (s->out_bits >= 8) {
|
||||
g722_data[g722_bytes++] = (uint8_t)(s->out_buffer & 0xFF);
|
||||
s->out_bits -= 8;
|
||||
s->out_buffer >>= 8;
|
||||
}
|
||||
#else
|
||||
g722_data[g722_bytes++] = (uint8_t)code;
|
||||
#endif
|
||||
}
|
||||
return g722_bytes;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
/*- End of file ------------------------------------------------------------*/
|
||||
|
|
@ -173,12 +173,12 @@ if get_option('bluez5-codec-lc3').allowed() and lc3_dep.found()
|
|||
install_dir : spa_plugindir / 'bluez5')
|
||||
endif
|
||||
|
||||
if get_option('bluez5-codec-g722').allowed() and ffmpeg.allowed()
|
||||
if get_option('bluez5-codec-g722').allowed()
|
||||
bluez_codec_g722 = shared_library('spa-codec-bluez5-g722',
|
||||
[ 'asha-codec-g722.c', 'media-codecs.c' ],
|
||||
[ 'g722/g722_encode.c', 'asha-codec-g722.c', 'media-codecs.c' ],
|
||||
include_directories : [ configinc ],
|
||||
c_args : codec_args,
|
||||
dependencies : [ spa_dep, avcodec_dep, avformat_dep, avutil_dep ],
|
||||
dependencies : [ spa_dep ],
|
||||
install : true,
|
||||
install_dir : spa_plugindir / 'bluez5')
|
||||
endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue