Skip to content

Commit

Permalink
MT#54294 add GPU support
Browse files Browse the repository at this point in the history
Change-Id: I035eff68a4448ad1b2f5b4520943626e1723fce7
  • Loading branch information
rfuchs committed Sep 15, 2023
1 parent 1238d2f commit 2fa121c
Show file tree
Hide file tree
Showing 11 changed files with 314 additions and 17 deletions.
1 change: 1 addition & 0 deletions daemon/.ycm_extra_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
'-DWITH_TRANSCODING',
'-DHAVE_BCG729',
'-DHAVE_MQTT',
'-DHAVE_CUDECS',
'-D__csh_lookup(x)=str_hash(x)',
'-DCSH_LOOKUP(x)=' + csh_lookup_str,
'-O2',
Expand Down
1 change: 1 addition & 0 deletions daemon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ endif

ifeq ($(with_transcoding),yes)
include ../lib/g729.Makefile
include ../lib/cudecs.Makefile
endif

include ../lib/mqtt.Makefile
Expand Down
38 changes: 33 additions & 5 deletions daemon/codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ struct codec_ssrc_handler {
struct codec_handler *handler;
decoder_t *decoder;
encoder_t *encoder;
codec_chain_t *chain;
format_t encoder_format;
int bitrate;
int ptime;
Expand Down Expand Up @@ -3523,6 +3524,8 @@ static void __delay_buffer_free(void *p) {
mutex_destroy(&dbuf->lock);
}
static void __dtx_setup(struct codec_ssrc_handler *ch) {
if (!ch->decoder)
return;
if (!decoder_has_dtx(ch->decoder))
return;

Expand Down Expand Up @@ -3765,6 +3768,21 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
.channels = h->dest_pt.channels,
.format = -1,
};

// see if there's a complete codec chain usable for this
if (!h->pcm_dtmf_detect)
ch->chain = codec_chain_new(h->source_pt.codec_def, &dec_format,
h->dest_pt.codec_def, &enc_format,
ch->bitrate, ch->ptime);

if (ch->chain) {
ilogs(codec, LOG_DEBUG, "Using codec chain to transcode from " STR_FORMAT " to " STR_FORMAT,
STR_FMT(&h->source_pt.encoding_with_params),
STR_FMT(&h->dest_pt.encoding_with_params));

return &ch->h;
}

ch->encoder = encoder_new();
if (!ch->encoder)
goto err;
Expand Down Expand Up @@ -4096,10 +4114,20 @@ static int __rtp_decode(struct codec_ssrc_handler *ch, struct codec_ssrc_handler
struct transcode_packet *packet, struct media_packet *mp)
{
int ret = 0;
if (packet)
ret = decoder_input_data_ptime(ch->decoder, packet->payload, packet->ts, &mp->ptime,
ch->handler->packet_decoded,
ch, mp);
if (packet) {
if (ch->chain) {
static const struct fraction chain_fact = {1,1};
AVPacket *pkt = codec_chain_input_data(ch->chain, packet->payload, packet->ts);
assert(pkt != NULL);
packet_encoded_packetize(pkt, ch, mp, packetizer_passthrough, NULL, &chain_fact,
packet_encoded_tx);
av_packet_unref(pkt);
}
else
ret = decoder_input_data_ptime(ch->decoder, packet->payload, packet->ts, &mp->ptime,
ch->handler->packet_decoded,
ch, mp);
}
__buffer_delay_seq(input_ch->handler->delay_buffer, mp, -1);
return ret;
}
Expand All @@ -4111,7 +4139,7 @@ static int packet_decode(struct codec_ssrc_handler *ch, struct codec_ssrc_handle
if (!ch->csch.first_ts)
ch->csch.first_ts = packet->ts;

if (ch->decoder->def->dtmf) {
if (ch->decoder && ch->decoder->def->dtmf) {
if (packet_dtmf_event(ch, input_ch, packet, mp) == -1)
goto out;
}
Expand Down
1 change: 1 addition & 0 deletions lib/.ycm_extra_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
'-DRE_PLUGIN_DIR="/usr/lib/rtpengine"',
'-DWITH_IPTABLES_OPTION',
'-DHAVE_BCG729',
'-DHAVE_CUDECS',
'-D__csh_lookup(x)=str_hash(x)',
'-DCSH_LOOKUP(x)=' + csh_lookup_str,
'-O2',
Expand Down
3 changes: 3 additions & 0 deletions lib/auxlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ void config_load(int *argc, char ***argv, GOptionEntry *app_entries, const char
{ "thread-stack", 0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->thread_stack, "Thread stack size in kB", "INT" },
{ "poller-size", 0,0, G_OPTION_ARG_INT, &rtpe_common_config_ptr->poller_size, "Max poller items per iteration", "INT" },
{ "evs-lib-path", 0,0, G_OPTION_ARG_FILENAME, &rtpe_common_config_ptr->evs_lib_path, "Location of .so for 3GPP EVS codec", "FILE" },
#ifdef HAVE_CUDECS
{ "cudecs", 0,0, G_OPTION_ARG_NONE, &rtpe_common_config_ptr->cudecs, "Enable usage of CUDA codecs", NULL },
#endif
{ NULL, }
};
#undef ll
Expand Down
1 change: 1 addition & 0 deletions lib/auxlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ struct rtpengine_common_config {
int poller_size;
int max_log_line_length;
char *evs_lib_path;
int cudecs;
};

extern struct rtpengine_common_config *rtpe_common_config_ptr;
Expand Down
237 changes: 235 additions & 2 deletions lib/codeclib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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[] = {
{
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
}

0 comments on commit 2fa121c

Please sign in to comment.