342 lines
9.2 KiB
C++
342 lines
9.2 KiB
C++
#include "MT_EvsCodec.h"
|
|
#include <set>
|
|
#include <map>
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* rate2AMRWB_IOmode()
|
|
*
|
|
* lookup AMRWB IO mode
|
|
*-------------------------------------------------------------------*/
|
|
namespace evs {
|
|
extern Word16 rate2AMRWB_IOmode(
|
|
Word32 rate /* i: bit rate */
|
|
);
|
|
|
|
/*Revers Function*/
|
|
extern Word16 AMRWB_IOmode2rate(
|
|
Word32 mode
|
|
);
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* rate2EVSmode()
|
|
*
|
|
* lookup EVS mode
|
|
*-------------------------------------------------------------------*/
|
|
extern Word16 rate2EVSmode(
|
|
Word32 rate /* i: bit rate */
|
|
);
|
|
|
|
/*Revers Function*/
|
|
extern Word16 EVSmode2rate(
|
|
Word32 mode
|
|
);
|
|
|
|
#define CMR_OFF -1
|
|
#define CMR_ON 0
|
|
#define CMR_ONLY 1
|
|
|
|
}
|
|
|
|
static const std::map<int, std::set<int>> BitrateToBandwidth_Tab{
|
|
{5900, {NB, WB}},
|
|
{7200, {NB, WB}},
|
|
{8000, {NB, WB}},
|
|
{9600, {NB, WB, SWB}},
|
|
{13200, {NB, WB, SWB}}, //if channel aware mode - WB, SWB
|
|
{16400, {NB, WB, SWB, FB}},
|
|
{24400, {NB, WB, SWB, FB}},
|
|
{32000, {WB, SWB, FB}},
|
|
{48000, {WB, SWB, FB}},
|
|
{64000, {WB, SWB, FB}},
|
|
{96000, {WB, SWB, FB}},
|
|
{128000, {WB, SWB, FB}}
|
|
};
|
|
|
|
/* Protected payload size/Fixed bitrate to EVS ()*/
|
|
static const std::map<int, int> Bitrate2PayloadSize_EVSAMR_WB{
|
|
/*{bitrate, payload size}*/
|
|
{ SID_1k75, 56}, //AMR-WB I/O SIB
|
|
{ACELP_6k60, 136},
|
|
{ACELP_8k85, 184},
|
|
{ACELP_12k65, 256},
|
|
{ACELP_14k25, 288},
|
|
{ACELP_15k85, 320},
|
|
{ACELP_18k25, 368},
|
|
{ACELP_19k85, 400},
|
|
{ACELP_23k05, 464},
|
|
{ACELP_23k85, 480}
|
|
};
|
|
|
|
static const std::map<int, int> Bitrate2PayloadSize_EVS{
|
|
/*{bitrate, payload size}*/
|
|
{FRAME__NO_DATA, 0},
|
|
{SID_2k40, 48}, //EVS Primary SID
|
|
{PPP_NELP_2k80, 56}, //special for full header
|
|
{ACELP_7k20, 144},
|
|
{ACELP_8k00, 160},
|
|
{ACELP_9k60, 192},
|
|
{ACELP_13k20, 264},
|
|
{ACELP_16k40, 328},
|
|
{ACELP_24k40, 488},
|
|
{ACELP_32k, 640},
|
|
{ACELP_48k, 960},
|
|
{ACELP_64k, 1280},
|
|
{HQ_96k, 1920},
|
|
{HQ_128k, 2560}
|
|
};
|
|
|
|
/* Protected payload size/Fixed bitrate to EVS ()*/
|
|
static const std::map<int, int> FixedPayload_EVSPrimary{
|
|
/*{payload size , bitrate}*/
|
|
{48, 2400}, //EVS Primary SID
|
|
{56, 2800}, //special for full header
|
|
{144, 7200},
|
|
{160, 8000},
|
|
{192, 9600},
|
|
{264, 13200},
|
|
{328, 16400},
|
|
{488, 24400},
|
|
{640, 32000},
|
|
{960, 48000},
|
|
{1280, 64000},
|
|
{1920, 96000},
|
|
{2560, 128000}
|
|
};
|
|
|
|
static const std::map<int, int> FixedPayload_EVSAMR_WB{
|
|
/*{payload size , bitrate}*/
|
|
{136, 6600},
|
|
{184, 8850},
|
|
{256, 12650},
|
|
{288, 14250},
|
|
{320, 15850},
|
|
{368, 18250},
|
|
{400, 19850},
|
|
{464, 23050},
|
|
{480, 23850}
|
|
};
|
|
|
|
namespace MT
|
|
{
|
|
|
|
EVSCodec::EVSFactory::EVSFactory(StreamParameters& sp) : _sp(sp)
|
|
{}
|
|
|
|
int EVSCodec::EVSFactory::samplerate()
|
|
{
|
|
switch (_sp.bw)
|
|
{
|
|
case 0: return 8000;
|
|
case 1: return 16000;
|
|
case 2: return 32000;
|
|
case 3: return 48000;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int EVSCodec::EVSFactory::payloadType()
|
|
{
|
|
return _sp.ptype;
|
|
}
|
|
|
|
PCodec EVSCodec::EVSFactory::create()
|
|
{
|
|
return std::static_pointer_cast<Codec>(std::make_shared<EVSCodec>(_sp));
|
|
}
|
|
|
|
EVSCodec::EVSCodec(): EVSCodec(StreamParameters())
|
|
{}
|
|
|
|
EVSCodec::EVSCodec(const StreamParameters &sp)
|
|
{
|
|
EVSCodec::sp = sp;
|
|
|
|
// Metadata only - the heavy decoder state is created lazily (ensureDecoder()).
|
|
mOutputFs = outputFsFromBw(sp.bw);
|
|
}
|
|
|
|
int EVSCodec::outputFsFromBw(int bw)
|
|
{
|
|
switch (bw)
|
|
{
|
|
case NB: return 8000;
|
|
case WB: return 16000;
|
|
case SWB: return 32000;
|
|
case FB: return 48000;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void EVSCodec::ensureDecoder()
|
|
{
|
|
if (st_dec)
|
|
return;
|
|
|
|
if ((st_dec = reinterpret_cast<evs::Decoder_State*>(malloc(sizeof(evs::Decoder_State)))) == nullptr)
|
|
throw std::bad_alloc();
|
|
|
|
initDecoder(sp);
|
|
}
|
|
|
|
EVSCodec::~EVSCodec()
|
|
{
|
|
if (st_dec)
|
|
{
|
|
destroy_decoder(st_dec);
|
|
free(st_dec); st_dec = nullptr;
|
|
}
|
|
}
|
|
|
|
Codec::Info EVSCodec::info() {
|
|
return {
|
|
.mName = MT_EVS_CODECNAME,
|
|
.mSamplerate = mOutputFs,
|
|
.mChannels = 1,
|
|
.mPcmLength = mOutputFs / 1000 * sp.ptime * 2,
|
|
.mFrameTime = sp.ptime,
|
|
.mRtpLength = 0
|
|
};
|
|
}
|
|
|
|
|
|
Codec::EncodeResult EVSCodec::encode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
|
{
|
|
// Encoding is not supported yet.
|
|
return {.mEncoded = 0};
|
|
}
|
|
|
|
Codec::DecodeResult EVSCodec::decode(std::span<const uint8_t> input, std::span<uint8_t> output)
|
|
{
|
|
ensureDecoder();
|
|
|
|
if (output.size_bytes() < pcmLength())
|
|
return {.mDecoded = 0};
|
|
|
|
std::string buffer;
|
|
|
|
// Check if we get payload with CMR
|
|
auto payload_iter = FixedPayload_EVSPrimary.find((input.size_bytes() - 2) * 8);
|
|
if (payload_iter == FixedPayload_EVSPrimary.end())
|
|
{
|
|
// Check if we get payload with ToC and without CMR
|
|
payload_iter = FixedPayload_EVSPrimary.find((input.size_bytes() - 1) * 8);
|
|
if (payload_iter == FixedPayload_EVSPrimary.end())
|
|
{
|
|
// Maybe there is no ToC ?
|
|
payload_iter = FixedPayload_EVSPrimary.find(input.size_bytes() * 8);
|
|
if (payload_iter == FixedPayload_EVSPrimary.end())
|
|
{
|
|
// Bad payload size at all
|
|
return {.mDecoded = 0};
|
|
}
|
|
/* Add ToC byte.
|
|
* WARNING maybe it will be work incorrect with 56bit payload,
|
|
* see 3GPP TS 26.445 Annex A, A.2.1.3 */
|
|
char c = evs::rate2EVSmode(FixedPayload_EVSPrimary.find(input.size_bytes() * 8)->second);
|
|
buffer += c;
|
|
buffer += std::string(reinterpret_cast<const char*>(input.data()), input.size_bytes());
|
|
}
|
|
else
|
|
buffer = std::string(reinterpret_cast<const char*>(input.data()), input.size_bytes());
|
|
}
|
|
else // Skip CMR byte
|
|
buffer = std::string(reinterpret_cast<const char*>(input.data()) + 1, input.size_bytes()-1);
|
|
|
|
|
|
// Output buffer for 48 KHz
|
|
float data[L_FRAME48k];
|
|
int offset = 0;
|
|
|
|
/* Decode process */
|
|
size_t buffer_processed = 0;
|
|
|
|
while (st_dec->bitstreamformat == evs::G192 ? read_indices(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0) : read_indices_mime(st_dec, buffer.c_str(), buffer.size(), &buffer_processed, 0))
|
|
{
|
|
if (st_dec->codec_mode == MODE1)
|
|
{
|
|
if (st_dec->Opt_AMR_WB)
|
|
{
|
|
amr_wb_dec(st_dec, data);
|
|
}
|
|
else
|
|
{
|
|
evs_dec(st_dec, data, evs::FRAMEMODE_NORMAL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!st_dec->bfi)
|
|
{
|
|
evs_dec(st_dec, data, evs::FRAMEMODE_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
evs_dec(st_dec, data, evs::FRAMEMODE_MISSING);
|
|
}
|
|
}
|
|
|
|
/* convert 'float' output data to 'short' */
|
|
evs::syn_output(data, static_cast<short>(pcmLength() / 2), reinterpret_cast<short*>(output.data()) + offset);
|
|
offset += pcmLength() / 2;
|
|
if (st_dec->ini_frame < MAX_FRAME_COUNTER)
|
|
{
|
|
st_dec->ini_frame++;
|
|
}
|
|
}
|
|
|
|
return {.mDecoded = (size_t)pcmLength()};
|
|
}
|
|
|
|
size_t EVSCodec::plc(int lostFrames, std::span<uint8_t> output)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void EVSCodec::initDecoder(const StreamParameters& sp)
|
|
{
|
|
/* set to NULL, to avoid reading of uninitialized memory in case of early abort */
|
|
st_dec->cldfbAna = st_dec->cldfbBPF = st_dec->cldfbSyn = nullptr;
|
|
st_dec->hFdCngDec = nullptr;
|
|
st_dec->codec_mode = 0; /* unknown before first frame */
|
|
st_dec->Opt_AMR_WB = 0;
|
|
st_dec->Opt_VOIP = 0;
|
|
|
|
st_dec->bitstreamformat = evs::G192;
|
|
st_dec->amrwb_rfc4867_flag = -1;
|
|
|
|
/*Set MIME type*/
|
|
if (sp.mime) {
|
|
st_dec->bitstreamformat = evs::MIME;
|
|
st_dec->amrwb_rfc4867_flag = 0;
|
|
}
|
|
/*Set Bandwidth*/
|
|
switch (sp.bw) {
|
|
case NB :
|
|
st_dec->output_Fs = 8000;
|
|
break;
|
|
case WB:
|
|
st_dec->output_Fs = 16000;
|
|
break;
|
|
case SWB:
|
|
st_dec->output_Fs = 32000;
|
|
break;
|
|
case FB:
|
|
st_dec->output_Fs = 48000;
|
|
break;
|
|
}
|
|
// st_enc->input_Fs = st_dec->output_Fs; //TODO: remove when func initEncoder() is added
|
|
/*------------------------------------------------------------------------------------------*
|
|
* Allocate memory for static variables
|
|
* Decoder initialization
|
|
*------------------------------------------------------------------------------------------*/
|
|
|
|
// TODO: add ability of reinit Decoder_state, may be need use destroy_decoder()
|
|
init_decoder(st_dec);
|
|
reset_indices_dec(st_dec);
|
|
|
|
srand(static_cast<unsigned int>(time(nullptr)));
|
|
}
|
|
|
|
} // end of namespace MT
|