|
|
|
@ -11,6 +11,11 @@ |
|
|
|
#include <bcg729/decoder.h> |
|
|
|
#endif |
|
|
|
#include <opus.h> |
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
#include <cudecs/g711opus.h> |
|
|
|
#include <cudecs/gpu-utils.h> |
|
|
|
#include <cudecs/gpu-opus.h> |
|
|
|
#endif |
|
|
|
#include "str.h" |
|
|
|
#include "log.h" |
|
|
|
#include "loglib.h" |
|
|
|
@ -32,7 +37,6 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static packetizer_f packetizer_passthrough; // pass frames as they arrive in AVPackets |
|
|
|
static packetizer_f packetizer_samplestream; // flat stream of samples |
|
|
|
static packetizer_f packetizer_amr; |
|
|
|
|
|
|
|
@ -139,6 +143,34 @@ static select_encoder_format_f evs_select_encoder_format; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct codec_chain_s { |
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
union { |
|
|
|
struct { |
|
|
|
gpu_pcmu2opus_runner *runner; |
|
|
|
gpu_float2opus *enc; |
|
|
|
} pcmu2opus; |
|
|
|
struct { |
|
|
|
gpu_pcma2opus_runner *runner; |
|
|
|
gpu_float2opus *enc; |
|
|
|
} pcma2opus; |
|
|
|
struct { |
|
|
|
gpu_opus2pcmu_runner *runner; |
|
|
|
gpu_opus2float *dec; |
|
|
|
} opus2pcmu; |
|
|
|
struct { |
|
|
|
gpu_opus2pcma_runner *runner; |
|
|
|
gpu_opus2float *dec; |
|
|
|
} opus2pcma; |
|
|
|
} u; |
|
|
|
AVPacket *avpkt; |
|
|
|
int (*run)(codec_chain_t *c, const str *data, unsigned long ts, AVPacket *); |
|
|
|
#endif |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const codec_type_t codec_type_avcodec = { |
|
|
|
.def_init = avc_def_init, |
|
|
|
@ -239,6 +271,14 @@ static const codec_type_t codec_type_bcg729 = { |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
static gpu_pcma2opus_runner *pcma2opus_runner; |
|
|
|
static gpu_pcmu2opus_runner *pcmu2opus_runner; |
|
|
|
static gpu_opus2pcmu_runner *opus2pcmu_runner; |
|
|
|
static gpu_opus2pcma_runner *opus2pcma_runner; |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct codec_def_s __codec_defs[] = { |
|
|
|
{ |
|
|
|
@ -1223,6 +1263,31 @@ void codeclib_init(int print) { |
|
|
|
codecs_ht = g_hash_table_new(str_case_hash, str_case_equal); |
|
|
|
codecs_ht_by_av = g_hash_table_new(g_direct_hash, g_direct_equal); |
|
|
|
|
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
if (rtpe_common_config_ptr->cudecs) { |
|
|
|
if (!gpu_init()) |
|
|
|
die("Failed to initialise CUDA codecs"); |
|
|
|
|
|
|
|
pcma2opus_runner = gpu_pcma2opus_runner_new(4, 3000, 160); |
|
|
|
if (!pcma2opus_runner) |
|
|
|
die("Failed to initialise GPU pcma2opus"); |
|
|
|
|
|
|
|
pcmu2opus_runner = gpu_pcmu2opus_runner_new(4, 3000, 160); |
|
|
|
if (!pcmu2opus_runner) |
|
|
|
die("Failed to initialise GPU pcmu2opus"); |
|
|
|
|
|
|
|
opus2pcmu_runner = gpu_opus2pcmu_runner_new(4, 3000, 160); |
|
|
|
if (!opus2pcmu_runner) |
|
|
|
die("Failed to initialise GPU opus2pcmu"); |
|
|
|
|
|
|
|
opus2pcma_runner = gpu_opus2pcma_runner_new(4, 3000, 160); |
|
|
|
if (!opus2pcma_runner) |
|
|
|
die("Failed to initialise GPU opus2pcma"); |
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "CUDA codecs initialised"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
for (int i = 0; i < G_N_ELEMENTS(__codec_defs); i++) { |
|
|
|
// add to hash table |
|
|
|
struct codec_def_s *def = &__codec_defs[i]; |
|
|
|
@ -1771,7 +1836,7 @@ int encoder_input_fifo(encoder_t *enc, AVFrame *frame, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t *enc) { |
|
|
|
int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t *enc) { |
|
|
|
if (!pkt) |
|
|
|
return -1; |
|
|
|
if (output->len < pkt->size) { |
|
|
|
@ -4589,3 +4654,171 @@ static void evs_def_init(struct codec_def_s *def) { |
|
|
|
static int evs_dtx(decoder_t *dec, GQueue *out, int ptime) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
int codec_chain_pcmu2opus_run(codec_chain_t *c, const str *data, unsigned long ts, AVPacket *pkt) { |
|
|
|
ssize_t ret = gpu_pcmu2opus_runner_do(c->u.pcmu2opus.runner, c->u.pcmu2opus.enc, |
|
|
|
(unsigned char *) data->s, data->len, |
|
|
|
pkt->data, pkt->size); |
|
|
|
assert(ret > 0); |
|
|
|
|
|
|
|
pkt->size = ret; |
|
|
|
pkt->duration = data->len * 6L; |
|
|
|
pkt->pts = ts * 6L; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int codec_chain_pcma2opus_run(codec_chain_t *c, const str *data, unsigned long ts, AVPacket *pkt) { |
|
|
|
ssize_t ret = gpu_pcma2opus_runner_do(c->u.pcma2opus.runner, c->u.pcma2opus.enc, |
|
|
|
(unsigned char *) data->s, data->len, |
|
|
|
pkt->data, pkt->size); |
|
|
|
assert(ret > 0); |
|
|
|
|
|
|
|
pkt->size = ret; |
|
|
|
pkt->duration = data->len * 6L; |
|
|
|
pkt->pts = ts * 6L; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int codec_chain_opus2pcmu_run(codec_chain_t *c, const str *data, unsigned long ts, AVPacket *pkt) { |
|
|
|
ssize_t ret = gpu_opus2pcmu_runner_do(c->u.opus2pcmu.runner, c->u.opus2pcmu.dec, |
|
|
|
(unsigned char *) data->s, data->len, |
|
|
|
pkt->data, pkt->size); |
|
|
|
assert(ret > 0); |
|
|
|
|
|
|
|
pkt->size = ret; |
|
|
|
pkt->duration = ret; |
|
|
|
pkt->pts = ts / 6L; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int codec_chain_opus2pcma_run(codec_chain_t *c, const str *data, unsigned long ts, AVPacket *pkt) { |
|
|
|
ssize_t ret = gpu_opus2pcma_runner_do(c->u.opus2pcma.runner, c->u.opus2pcma.dec, |
|
|
|
(unsigned char *) data->s, data->len, |
|
|
|
pkt->data, pkt->size); |
|
|
|
assert(ret > 0); |
|
|
|
|
|
|
|
pkt->size = ret; |
|
|
|
pkt->duration = ret; |
|
|
|
pkt->pts = ts / 6L; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
codec_chain_t *codec_chain_new(codec_def_t *src, format_t *src_format, codec_def_t *dst, |
|
|
|
format_t *dst_format, int bitrate, int ptime) |
|
|
|
{ |
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
if (!strcmp(dst->rtpname, "opus") && !strcmp(src->rtpname, "PCMA")) { |
|
|
|
if (src_format->clockrate != 8000) |
|
|
|
return NULL; |
|
|
|
if (src_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (dst_format->channels != 2) |
|
|
|
return NULL; |
|
|
|
if (dst_format->clockrate != 48000) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (!pcma2opus_runner) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
codec_chain_t *ret = g_slice_alloc0(sizeof(*ret)); |
|
|
|
ret->u.pcma2opus.enc = gpu_float2opus_new(bitrate); |
|
|
|
ret->u.pcma2opus.runner = pcma2opus_runner; |
|
|
|
ret->avpkt = av_packet_alloc(); |
|
|
|
ret->run = codec_chain_pcma2opus_run; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
else if (!strcmp(dst->rtpname, "opus") && !strcmp(src->rtpname, "PCMU")) { |
|
|
|
if (src_format->clockrate != 8000) |
|
|
|
return NULL; |
|
|
|
if (src_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (dst_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (dst_format->clockrate != 48000) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (!pcmu2opus_runner) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
codec_chain_t *ret = g_slice_alloc0(sizeof(*ret)); |
|
|
|
ret->u.pcmu2opus.enc = gpu_float2opus_new(bitrate); |
|
|
|
ret->u.pcmu2opus.runner = pcmu2opus_runner; |
|
|
|
ret->avpkt = av_packet_alloc(); |
|
|
|
ret->run = codec_chain_pcmu2opus_run; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
else if (!strcmp(dst->rtpname, "PCMU") && !strcmp(src->rtpname, "opus")) { |
|
|
|
if (dst_format->clockrate != 8000) |
|
|
|
return NULL; |
|
|
|
if (dst_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (src_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (src_format->clockrate != 48000) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (!opus2pcmu_runner) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
codec_chain_t *ret = g_slice_alloc0(sizeof(*ret)); |
|
|
|
ret->u.opus2pcmu.dec = gpu_opus2float_new(); |
|
|
|
ret->u.opus2pcmu.runner = opus2pcmu_runner; |
|
|
|
ret->avpkt = av_packet_alloc(); |
|
|
|
ret->run = codec_chain_opus2pcmu_run; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
else if (!strcmp(dst->rtpname, "PCMA") && !strcmp(src->rtpname, "opus")) { |
|
|
|
if (dst_format->clockrate != 8000) |
|
|
|
return NULL; |
|
|
|
if (dst_format->channels != 1) |
|
|
|
return NULL; |
|
|
|
if (src_format->channels != 2) |
|
|
|
return NULL; |
|
|
|
if (src_format->clockrate != 48000) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (!opus2pcma_runner) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
codec_chain_t *ret = g_slice_alloc0(sizeof(*ret)); |
|
|
|
ret->u.opus2pcma.dec = gpu_opus2float_new(); |
|
|
|
ret->u.opus2pcma.runner = opus2pcma_runner; |
|
|
|
ret->avpkt = av_packet_alloc(); |
|
|
|
ret->run = codec_chain_opus2pcma_run; |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
AVPacket *codec_chain_input_data(codec_chain_t *c, const str *data, unsigned long ts) { |
|
|
|
#ifdef HAVE_CUDECS |
|
|
|
av_new_packet(c->avpkt, MAX_OPUS_FRAME_SIZE * MAX_OPUS_FRAMES_PER_PACKET + MAX_OPUS_HEADER_SIZE); |
|
|
|
|
|
|
|
int ret = c->run(c, data, ts, c->avpkt); |
|
|
|
assert(ret == 0); |
|
|
|
|
|
|
|
return c->avpkt; |
|
|
|
|
|
|
|
#else |
|
|
|
return NULL; |
|
|
|
#endif |
|
|
|
} |