TT#35456 implement RFC 4867

Fixes AMR transcoding. Some features yet unsupported.

Fixes #498

Change-Id: I1075a539a7a7dab9106df9ef49b8bda2484b97ec
changes/55/20655/9
Richard Fuchs 7 years ago
parent 4d4abfabf8
commit 895fa96054

@ -8,9 +8,10 @@ all:
$(MAKE) -C daemon
$(MAKE) -C recording-daemon
$(MAKE) -C iptables-extension
$(MAKE) -C t
with-kernel:
$(MAKE)
$(MAKE) all
$(MAKE) -C kernel-module
distclean clean:
@ -18,6 +19,7 @@ distclean clean:
$(MAKE) -C recording-daemon clean
$(MAKE) -C iptables-extension clean
$(MAKE) -C kernel-module clean
$(MAKE) -C t clean
rm -rf project.tgz cov-int
.DEFAULT:
@ -25,6 +27,7 @@ distclean clean:
$(MAKE) -C recording-daemon $@
$(MAKE) -C iptables-extension $@
$(MAKE) -C kernel-module $@
$(MAKE) -C t
coverity:
cov-build --dir cov-int $(MAKE)

@ -478,6 +478,7 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca
ret->channels = channels;
ret->bitrate = bitrate;
ret->ptime = ptime;
ret->format_parameters = STR_EMPTY;
const codec_def_t *def = codec_find(&ret->encoding, 0);
ret->codec_def = def;
@ -490,6 +491,8 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca
ret->channels = def->default_channels;
if (!ret->ptime)
ret->ptime = def->default_ptime;
if ((!ret->format_parameters.s || !ret->format_parameters.s[0]) && def->default_fmtp)
str_init(&ret->format_parameters, (char *) def->default_fmtp);
if (def->init)
def->init(ret);
@ -527,7 +530,6 @@ struct rtp_payload_type *codec_make_payload_type(const str *codec_str, struct ca
str_init(&ret->encoding_with_params, full_encoding);
str_init(&ret->encoding_parameters, params);
ret->format_parameters = STR_EMPTY;
__rtp_payload_type_dup(media->call, ret);
@ -587,14 +589,14 @@ static struct ssrc_entry *__ssrc_handler_new(void *p) {
ch->encoder = encoder_new();
if (!ch->encoder)
goto err;
if (encoder_config(ch->encoder, h->dest_pt.codec_def,
if (encoder_config_fmtp(ch->encoder, h->dest_pt.codec_def,
h->dest_pt.bitrate ? : h->dest_pt.codec_def->default_bitrate,
ch->ptime,
&enc_format, &ch->encoder_format))
&enc_format, &ch->encoder_format, &h->dest_pt.format_parameters))
goto err;
ch->decoder = decoder_new_fmt(h->source_pt.codec_def, h->source_pt.clock_rate, h->source_pt.channels,
&ch->encoder_format);
ch->decoder = decoder_new_fmtp(h->source_pt.codec_def, h->source_pt.clock_rate, h->source_pt.channels,
&ch->encoder_format, &h->source_pt.format_parameters);
if (!ch->decoder)
goto err;
@ -649,6 +651,7 @@ static int __packet_encoded(encoder_t *enc, void *u1, void *u2) {
while (1) {
// figure out how big of a buffer we need
unsigned int payload_len = MAX(enc->avpkt.size, ch->bytes_per_packet);
payload_len += 16; // extra room for certain protocols, e.g. AMR framing
unsigned int pkt_len = sizeof(struct rtp_header) + payload_len + RTP_BUFFER_TAIL_ROOM;
// prepare our buffers
char *buf = malloc(pkt_len);
@ -661,7 +664,7 @@ static int __packet_encoded(encoder_t *enc, void *u1, void *u2) {
if (in_pkt)
ilog(LOG_DEBUG, "Adding %i bytes to packetizer", in_pkt->size);
int ret = ch->handler->dest_pt.codec_def->packetizer(in_pkt,
ch->sample_buffer, &inout);
ch->sample_buffer, &inout, enc);
if (G_UNLIKELY(ret == -1)) {
// nothing

@ -0,0 +1,79 @@
#ifndef _BITSTR_H_
#define _BITSTR_H_
#include "str.h"
#include <assert.h>
struct bitstr_s {
str s;
unsigned int bit_offset; // leading consumed bits
};
typedef struct bitstr_s bitstr;
INLINE void bitstr_init(bitstr *b, const str *s) {
b->s = *s;
b->bit_offset = 0;
}
INLINE int bitstr_shift_ret(bitstr *b, unsigned int bits, str *ret) {
if (!bits)
return 0;
// check if we have enough
if (bits > b->s.len * 8 - b->bit_offset)
return -1;
unsigned int to_copy = (bits + b->bit_offset + 7) / 8;
if (ret) {
assert(ret->len >= to_copy);
ret->len = to_copy;
memcpy(ret->s, b->s.s, to_copy);
unsigned char *ret_s = (unsigned char *) ret->s; // avoid bitshifts on signed chars
// we have to bit-shift the entire string if there was a leading offset
if (b->bit_offset) {
unsigned int left = bits;
unsigned int c = 0;
while (b->bit_offset + left > 8) {
// enough to fill one output byte from two consecutive input bytes
ret_s[c] <<= b->bit_offset;
ret_s[c] |= ret_s[c + 1] >> (8 - b->bit_offset);
if (left <= 8) {
// final trailing bits overlapping bytes: truncate
ret_s[c] &= 0xff << (8 - left);
left = 0;
ret->len--;
}
else
left -= 8;
c++;
}
if (left) {
// last byte has the remainder
ret_s[c] <<= b->bit_offset;
ret_s[c] &= 0xff << (8 - left);
}
}
else {
// truncate last byte if needed
unsigned int bits_left = bits % 8;
if (bits_left)
ret_s[to_copy - 1] &= 0xff << (8 - bits_left);
}
}
b->bit_offset += bits;
unsigned int int_bytes = b->bit_offset / 8;
int shift_ret = str_shift(&b->s, int_bytes);
assert(shift_ret == 0);
b->bit_offset -= int_bytes * 8;
return 0;
}
INLINE int bitstr_shift(bitstr *b, unsigned int bits) {
return bitstr_shift_ret(b, bits, NULL);
}
#endif

@ -13,6 +13,7 @@
#include "loglib.h"
#include "resample.h"
#include "rtplib.h"
#include "bitstr.h"
@ -34,18 +35,24 @@
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;
static format_init_f opus_init;
static set_options_f opus_set_options;
static set_enc_options_f opus_set_enc_options;
static set_enc_options_f amr_set_enc_options;
static set_dec_options_f amr_set_dec_options;
static void avc_def_init(codec_def_t *);
static const char *avc_decoder_init(decoder_t *);
static const char *avc_decoder_init(decoder_t *, const str *);
static int avc_decoder_input(decoder_t *dec, const str *data, GQueue *out);
static void avc_decoder_close(decoder_t *);
static const char *avc_encoder_init(encoder_t *enc);
static const char *avc_encoder_init(encoder_t *enc, const str *);
static int avc_encoder_input(encoder_t *enc, AVFrame **frame);
static void avc_encoder_close(encoder_t *enc);
static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out);
@ -58,15 +65,24 @@ static const codec_type_t codec_type_avcodec = {
.encoder_input = avc_encoder_input,
.encoder_close = avc_encoder_close,
};
static const codec_type_t codec_type_amr = {
.def_init = avc_def_init,
.decoder_init = avc_decoder_init,
.decoder_input = amr_decoder_input,
.decoder_close = avc_decoder_close,
.encoder_init = avc_encoder_init,
.encoder_input = avc_encoder_input,
.encoder_close = avc_encoder_close,
};
#ifdef HAVE_BCG729
static packetizer_f packetizer_g729; // aggregate some frames into packets
static void bcg729_def_init(codec_def_t *);
static const char *bcg729_decoder_init(decoder_t *);
static const char *bcg729_decoder_init(decoder_t *, const str *);
static int bcg729_decoder_input(decoder_t *dec, const str *data, GQueue *out);
static void bcg729_decoder_close(decoder_t *);
static const char *bcg729_encoder_init(encoder_t *enc);
static const char *bcg729_encoder_init(encoder_t *enc, const str *);
static int bcg729_encoder_input(encoder_t *enc, AVFrame **frame);
static void bcg729_encoder_close(encoder_t *enc);
@ -212,7 +228,7 @@ static codec_def_t __codec_defs[] = {
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.init = opus_init,
.set_options = opus_set_options,
.set_enc_options = opus_set_enc_options,
},
{
.rtpname = "vorbis",
@ -294,9 +310,12 @@ static codec_def_t __codec_defs[] = {
.default_channels = 1,
.default_bitrate = 6600,
.default_ptime = 20,
.packetizer = packetizer_passthrough,
.default_fmtp = "octet-align=1",
.packetizer = packetizer_amr,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.codec_type = &codec_type_amr,
.set_enc_options = amr_set_enc_options,
.set_dec_options = amr_set_dec_options,
},
{
.rtpname = "AMR-WB",
@ -306,9 +325,12 @@ static codec_def_t __codec_defs[] = {
.default_channels = 1,
.default_bitrate = 14250,
.default_ptime = 20,
.packetizer = packetizer_passthrough,
.default_fmtp = "octet-align=1",
.packetizer = packetizer_amr,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.codec_type = &codec_type_amr,
.set_enc_options = amr_set_enc_options,
.set_dec_options = amr_set_dec_options,
},
// pseudo-codecs
{
@ -368,17 +390,21 @@ enum media_type codec_get_type(const str *type) {
static const char *avc_decoder_init(decoder_t *ret) {
AVCodec *codec = ret->def->decoder;
static const char *avc_decoder_init(decoder_t *dec, const str *fmtp) {
AVCodec *codec = dec->def->decoder;
if (!codec)
return "codec not supported";
ret->u.avc.avcctx = avcodec_alloc_context3(codec);
if (!ret->u.avc.avcctx)
dec->u.avc.avcctx = avcodec_alloc_context3(codec);
if (!dec->u.avc.avcctx)
return "failed to alloc codec context";
ret->u.avc.avcctx->channels = ret->in_format.channels;
ret->u.avc.avcctx->sample_rate = ret->in_format.clockrate;
int i = avcodec_open2(ret->u.avc.avcctx, codec, NULL);
dec->u.avc.avcctx->channels = dec->in_format.channels;
dec->u.avc.avcctx->sample_rate = dec->in_format.clockrate;
if (dec->def->set_dec_options)
dec->def->set_dec_options(dec, fmtp);
int i = avcodec_open2(dec->u.avc.avcctx, codec, NULL);
if (i)
return "failed to open codec context";
@ -392,6 +418,12 @@ static const char *avc_decoder_init(decoder_t *ret) {
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt) {
return decoder_new_fmtp(def, clockrate, channels, resample_fmt, NULL);
}
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt,
const str *fmtp)
{
const char *err;
decoder_t *ret = NULL;
@ -412,7 +444,7 @@ decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels,
if (resample_fmt)
ret->out_format = *resample_fmt;
err = def->codec_type->decoder_init(ret);
err = def->codec_type->decoder_init(ret, fmtp);
if (err)
goto err;
@ -876,7 +908,7 @@ encoder_t *encoder_new() {
return ret;
}
static const char *avc_encoder_init(encoder_t *enc) {
static const char *avc_encoder_init(encoder_t *enc, const str *fmtp) {
enc->u.avc.codec = enc->def->encoder;
if (!enc->u.avc.codec)
return "output codec not found";
@ -911,8 +943,8 @@ static const char *avc_encoder_init(encoder_t *enc) {
enc->samples_per_frame = enc->u.avc.avcctx->frame_size;
enc->samples_per_packet = enc->samples_per_frame;
if (enc->def->set_options)
enc->def->set_options(enc);
if (enc->def->set_enc_options)
enc->def->set_enc_options(enc, fmtp);
int i = avcodec_open2(enc->u.avc.avcctx, enc->u.avc.codec, NULL);
if (i)
@ -923,6 +955,12 @@ static const char *avc_encoder_init(encoder_t *enc) {
int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime,
const format_t *requested_format, format_t *actual_format)
{
return encoder_config_fmtp(enc, def, bitrate, ptime, requested_format, actual_format, NULL);
}
int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime,
const format_t *requested_format, format_t *actual_format, const str *fmtp)
{
const char *err;
@ -941,7 +979,7 @@ int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptim
enc->ptime = ptime / def->clockrate_mult;
enc->bitrate = bitrate;
err = def->codec_type->encoder_init(enc);
err = def->codec_type->encoder_init(enc, fmtp);
if (err)
goto err;
@ -1133,7 +1171,7 @@ int encoder_input_fifo(encoder_t *enc, AVFrame *frame,
}
static int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output) {
static int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output, encoder_t *enc) {
if (!pkt)
return -1;
assert(output->len >= pkt->size);
@ -1144,7 +1182,7 @@ static int packetizer_passthrough(AVPacket *pkt, GString *buf, str *output) {
// returns: -1 = not enough data, nothing returned; 0 = returned a packet;
// 1 = returned a packet and there's more
static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_output) {
static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_output, encoder_t *enc) {
// avoid moving buffers around if possible:
// most common case: new input packet has just enough (or more) data as what we need
if (G_LIKELY(pkt && buf->len == 0 && pkt->size >= input_output->len)) {
@ -1167,6 +1205,9 @@ static int packetizer_samplestream(AVPacket *pkt, GString *buf, str *input_outpu
}
static void opus_init(struct rtp_payload_type *pt) {
if (pt->clock_rate != 48000) {
ilog(LOG_WARN, "Opus is only supported with a clock rate of 48 kHz");
@ -1216,7 +1257,7 @@ static void opus_init(struct rtp_payload_type *pt) {
ilog(LOG_DEBUG, "Using default bitrate of %i bps for %i-channel Opus", pt->bitrate, pt->channels);
}
static void opus_set_options(encoder_t *enc) {
static void opus_set_enc_options(encoder_t *enc, const str *fmtp) {
int ret;
if (enc->ptime)
if ((ret = av_opt_set_int(enc->u.avc.avcctx, "frame_duration", enc->ptime, 0)))
@ -1226,6 +1267,252 @@ static void opus_set_options(encoder_t *enc) {
#define AMR_FT_TYPES 14
const static unsigned int amr_bits_per_frame[AMR_FT_TYPES] = {
95, // 4.75 kbit/s // 0
103, // 5.15 kbit/s // 1
118, // 5.90 kbit/s // 2
134, // 6.70 kbit/s // 3
148, // 7.40 kbit/s // 4
159, // 7.95 kbit/s // 5
204, // 10.2 kbit/s // 6
244, // 12.2 kbit/s // 7
40, // comfort noise // 8
40, // comfort noise // 9
40, // comfort noise // 10
40, // comfort noise // 11
0, // invalid // 12
0, // invalid // 13
};
const static unsigned int amr_wb_bits_per_frame[AMR_FT_TYPES] = {
132, // 6.60 kbit/s // 0
177, // 8.85 kbit/s // 1
253, // 12.65 kbit/s // 2
285, // 14.25 kbit/s // 3
317, // 15.85 kbit/s // 4
365, // 18.25 kbit/s // 5
397, // 19.85 kbit/s // 6
461, // 23.05 kbit/s // 7
477, // 23.85 kbit/s // 8
40, // comfort noise // 9
0, // invalid // 10
0, // invalid // 11
0, // invalid // 12
0, // invalid // 13
};
static void amr_set_encdec_options(codec_options_t *opts, const str *fmtp, const codec_def_t *def) {
if (!strcmp(def->rtpname, "AMR"))
opts->amr.bits_per_frame = amr_bits_per_frame;
else
opts->amr.bits_per_frame = amr_wb_bits_per_frame;
if (!fmtp || !fmtp->s)
return;
// semicolon-separated key=value
str s = *fmtp;
str token, key;
while (str_token_sep(&token, &s, ';') == 0) {
if (str_token(&key, &token, '='))
continue;
if (!str_cmp(&key, "octet-align")) {
if (token.len == 1 && token.s[0] == '1')
opts->amr.octet_aligned = 1;
}
else if (!str_cmp(&key, "crc")) {
if (token.len == 1 && token.s[0] == '1') {
opts->amr.octet_aligned = 1;
opts->amr.crc = 1;
}
}
else if (!str_cmp(&key, "robust-sorting")) {
if (token.len == 1 && token.s[0] == '1') {
opts->amr.octet_aligned = 1;
opts->amr.robust_sorting = 1;
}
}
else if (!str_cmp(&key, "interleaving")) {
opts->amr.octet_aligned = 1;
opts->amr.interleaving = str_to_i(&token, 0);
}
// XXX other options
}
}
static void amr_set_enc_options(encoder_t *enc, const str *fmtp) {
amr_set_encdec_options(&enc->codec_options, fmtp, enc->def);
}
static void amr_set_dec_options(decoder_t *dec, const str *fmtp) {
amr_set_encdec_options(&dec->codec_options, fmtp, dec->def);
}
static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out) {
const char *err = NULL;
if (!data || !data->s)
goto err;
bitstr d;
bitstr_init(&d, data);
GQueue toc = G_QUEUE_INIT;
unsigned int ill = 0, ilp = 0;
unsigned char cmr_chr[2];
str cmr = STR_CONST_INIT_BUF(cmr_chr);
err = "no CMR";
if (bitstr_shift_ret(&d, 4, &cmr))
goto err;
// XXX handle CMR?
if (dec->codec_options.amr.octet_aligned) {
if (bitstr_shift(&d, 4))
goto err;
if (dec->codec_options.amr.interleaving) {
unsigned char ill_ilp_chr[2];
str ill_ilp = STR_CONST_INIT_BUF(ill_ilp_chr);
err = "no ILL/ILP";
if (bitstr_shift_ret(&d, 8, &ill_ilp))
goto err;
ill = ill_ilp_chr[0] >> 4;
ilp = ill_ilp_chr[0] & 0xf;
}
}
err = "ILP > ILL";
if (ilp > ill)
goto err;
err = "interleaving unimplemented";
if (ill)
goto err;
// TOC
int num_crcs = 0;
while (1) {
unsigned char toc_byte[2];
str toc_entry = STR_CONST_INIT_BUF(toc_byte);
err = "missing TOC entry";
if (bitstr_shift_ret(&d, 6, &toc_entry))
goto err;
if (dec->codec_options.amr.octet_aligned)
if (bitstr_shift(&d, 2))
goto err;
unsigned char ft = (toc_byte[0] >> 3) & 0xf;
if (ft != 14 && ft != 15) {
num_crcs++;
err = "invalid frame type";
if (ft >= AMR_FT_TYPES)
goto err;
if (dec->codec_options.amr.bits_per_frame[ft] == 0)
goto err;
}
g_queue_push_tail(&toc, GUINT_TO_POINTER(toc_byte[0]));
// no F bit = last TOC entry
if (!(toc_byte[0] & 0x80))
break;
}
if (dec->codec_options.amr.crc) {
// CRCs is one byte per frame
err = "missing CRC entry";
if (bitstr_shift(&d, num_crcs * 8))
goto err;
// XXX use/check CRCs
}
while (toc.length) {
unsigned char toc_byte = GPOINTER_TO_UINT(g_queue_pop_head(&toc));
unsigned char ft = (toc_byte >> 3) & 0xf;
if (ft >= AMR_FT_TYPES) // invalid
continue;
unsigned int bits = dec->codec_options.amr.bits_per_frame[ft];
// AMR encoder expects an octet aligned TOC byte plus the payload
unsigned char frame_buf[(bits + 7) / 8 + 1 + 1];
str frame = STR_CONST_INIT_BUF(frame_buf);
str_shift(&frame, 1);
err = "short frame";
if (bitstr_shift_ret(&d, bits, &frame))
goto err;
// add TOC byte
str_shift(&frame, -1);
frame.s[0] = toc_byte & 0x7c; // strip F bit, keep FT and Q, zero padding (01111100)
if (dec->codec_options.amr.octet_aligned && (bits % 8) != 0) {
unsigned int padding_bits = 8 - (bits % 8);
if (bitstr_shift(&d, padding_bits))
goto err;
}
err = "failed to decode AMR data";
if (avc_decoder_input(dec, &frame, out))
goto err;
}
return 0;
err:
if (err)
ilog(LOG_WARN, "Error unpacking AMR packet: %s", err);
return -1;
}
static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, encoder_t *enc) {
assert(pkt->size >= 1);
// CMR + TOC byte (already included) + optional ILL/ILP + optional CRC + payload
assert(output->len >= pkt->size + 3);
unsigned char toc = pkt->data[0];
unsigned char ft = (toc >> 3) & 0xf;
assert(ft <= 13);
unsigned int bits = enc->codec_options.amr.bits_per_frame[ft];
assert(bits != 0);
unsigned char *s = (unsigned char *) output->s; // for safe bit shifting
s[0] = '\xf0'; // no CMR req (4 bits)
if (enc->codec_options.amr.octet_aligned) {
unsigned int offset = 1; // CMR byte
if (enc->codec_options.amr.interleaving)
s[offset++] = 0; // no interleaving
if (enc->codec_options.amr.crc)
s[offset++] = 0; // not implemented
memcpy(s + offset, pkt->data, pkt->size);
output->len = pkt->size + offset;
return 0;
}
// bit shift TOC byte in (6 bits)
s[0] |= pkt->data[0] >> 4;
s[1] = (pkt->data[0] & 0x0c) << 4;
// bit shift payload in (shifted by 4+6 = 10 bits = 1 byte + 2 bits
for (int i = 1; i < pkt->size; i++) {
s[i] |= pkt->data[i] >> 2;
s[i+1] = pkt->data[i] << 6;
}
// is the last byte just padding?
bits += 4 + 6; // CMR and TOC
unsigned int bytes = (bits + 7) / 8;
output->len = bytes;
return 0;
}
#ifdef HAVE_BCG729
static void bcg729_def_init(codec_def_t *def) {
// test init
@ -1241,7 +1528,7 @@ static void bcg729_def_init(codec_def_t *def) {
}
}
static const char *bcg729_decoder_init(decoder_t *dec) {
static const char *bcg729_decoder_init(decoder_t *dec, const str *fmtp) {
dec->u.bcg729 = initBcg729DecoderChannel();
if (!dec->u.bcg729)
return "failed to initialize bcg729";
@ -1285,7 +1572,7 @@ static void bcg729_decoder_close(decoder_t *dec) {
dec->u.bcg729 = NULL;
}
static const char *bcg729_encoder_init(encoder_t *enc) {
static const char *bcg729_encoder_init(encoder_t *enc, const str *fmtp) {
enc->u.bcg729 = initBcg729EncoderChannel(0); // no VAD
if (!enc->u.bcg729)
return "failed to initialize bcg729";
@ -1329,13 +1616,13 @@ static void bcg729_encoder_close(encoder_t *enc) {
enc->u.bcg729 = NULL;
}
static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output) {
static int packetizer_g729(AVPacket *pkt, GString *buf, str *input_output, encoder_t *enc) {
// how many frames do we want?
int want_frames = input_output->len / 10;
// easiest case: we only want one frame. return what we got
if (want_frames == 1 && pkt)
return packetizer_passthrough(pkt, buf, input_output);
return packetizer_passthrough(pkt, buf, input_output, enc);
// any other case, we go through our buffer
str output = *input_output; // remaining output buffer

@ -29,6 +29,7 @@ struct resample_s;
struct seq_packet_s;
struct packet_sequencer_s;
struct rtp_payload_type;
union codec_options_u;
typedef struct codec_type_s codec_type_t;
typedef struct decoder_s decoder_t;
@ -37,10 +38,12 @@ typedef struct format_s format_t;
typedef struct resample_s resample_t;
typedef struct seq_packet_s seq_packet_t;
typedef struct packet_sequencer_s packet_sequencer_t;
typedef union codec_options_u codec_options_t;
typedef int packetizer_f(AVPacket *, GString *, str *);
typedef int packetizer_f(AVPacket *, GString *, str *, encoder_t *);
typedef void format_init_f(struct rtp_payload_type *);
typedef void set_options_f(encoder_t *);
typedef void set_enc_options_f(encoder_t *, const str *);
typedef void set_dec_options_f(decoder_t *, const str *);
@ -55,15 +58,26 @@ enum media_type {
struct codec_type_s {
void (*def_init)(codec_def_t *);
const char *(*decoder_init)(decoder_t *);
const char *(*decoder_init)(decoder_t *, const str *);
int (*decoder_input)(decoder_t *, const str *data, GQueue *);
void (*decoder_close)(decoder_t *);
const char *(*encoder_init)(encoder_t *);
const char *(*encoder_init)(encoder_t *, const str *);
int (*encoder_input)(encoder_t *, AVFrame **);
void (*encoder_close)(encoder_t *);
};
union codec_options_u {
struct {
int interleaving;
int octet_aligned:1;
int crc:1;
int robust_sorting:1;
const unsigned int *bits_per_frame;
} amr;
};
struct codec_def_s {
const char * const rtpname;
int clockrate_mult;
@ -73,13 +87,15 @@ struct codec_def_s {
int default_channels;
const int default_bitrate;
int default_ptime;
const char *default_fmtp;
packetizer_f * const packetizer;
const int bits_per_sample;
const enum media_type media_type;
// codec-specific callbacks
format_init_f *init;
set_options_f *set_options;
set_enc_options_f *set_enc_options;
set_dec_options_f *set_dec_options;
// filled in by codeclib_init()
str rtpname_str;
@ -107,6 +123,7 @@ struct resample_s {
struct decoder_s {
const codec_def_t *def;
codec_options_t codec_options;
format_t in_format,
out_format;
@ -135,6 +152,7 @@ struct encoder_s {
actual_format;
const codec_def_t *def;
codec_options_t codec_options;
union {
struct {
@ -177,6 +195,8 @@ enum media_type codec_get_type(const str *type);
decoder_t *decoder_new_fmt(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt);
decoder_t *decoder_new_fmtp(const codec_def_t *def, int clockrate, int channels, const format_t *resample_fmt,
const str *fmtp);
void decoder_close(decoder_t *dec);
int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts,
int (*callback)(decoder_t *, AVFrame *, void *u1, void *u2), void *u1, void *u2);
@ -185,6 +205,8 @@ int decoder_input_data(decoder_t *dec, const str *data, unsigned long ts,
encoder_t *encoder_new();
int encoder_config(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime,
const format_t *requested_format, format_t *actual_format);
int encoder_config_fmtp(encoder_t *enc, const codec_def_t *def, int bitrate, int ptime,
const format_t *requested_format, format_t *actual_format, const str *fmtp);
void encoder_close(encoder_t *);
void encoder_free(encoder_t *);
int encoder_input_data(encoder_t *enc, AVFrame *frame,

@ -12,7 +12,7 @@ debug:
dep: .depend
clean:
rm -f $(OBJS) $(TARGET) $(LIBSRCS) .depend core core.*
rm -f $(OBJS) $(TARGET) $(LIBSRCS) $(ADD_CLEAN) .depend core core.*
rm -f fix_frame_channel_layout.h fix_frame_channel_layout-test.[co]
.depend: $(SRCS) $(LIBSRCS) Makefile
@ -22,7 +22,7 @@ install:
$(OBJS): Makefile
$(LIBSRCS):
$(LIBSRCS): $(patsubst %,../lib/%,$(LIBSRCS))
rm -f "$@"
echo '/******** GENERATED FILE ********/' > "$@"
cat ../lib/"$@" >> "$@"

@ -44,6 +44,8 @@ void __ilog_np(int prio, const char *format, ...) __attribute__ ((format (printf
INLINE int get_log_level(void) {
if (!rtpe_common_config_ptr)
return 8;
return g_atomic_int_get(&rtpe_common_config_ptr->log_level);
}

@ -27,6 +27,8 @@ typedef struct _str str;
#define STR_NULL ((str) { NULL, 0 })
#define STR_EMPTY ((str) { "", 0 })
#define STR_CONST_INIT(str) { str, sizeof(str)-1 }
#define STR_CONST_INIT_LEN(str, len) { str, len }
#define STR_CONST_INIT_BUF(buf) { (char *) &buf, sizeof(buf) }
@ -60,6 +62,8 @@ INLINE str *str_chunk_insert(GStringChunk *c, const str *s);
INLINE int str_shift(str *s, int len);
/* eats the supplied string from the beginning of s. returns -1 if string head doesn't match */
INLINE int str_shift_cmp(str *s, const char *);
/* shifts the string by given length and returns the shifted part. returns -1 if string is too short */
INLINE int str_shift_ret(str *s, int len, str *ret);
/* binary compares str object with memory chunk of equal size */
INLINE int str_memcmp(const str *s, void *m);
/* locate a substring within a string, returns character index or -1 */
@ -113,8 +117,13 @@ INLINE char *str_end(const str *s) {
return s->s + s->len;
}
INLINE int str_shift(str *s, int len) {
return str_shift_ret(s, len, NULL);
}
INLINE int str_shift_ret(str *s, int len, str *ret) {
if (s->len < len)
return -1;
if (ret)
str_init_len(ret, s->s, len);
s->s += len;
s->len -= len;
return 0;

13
t/.gitignore vendored

@ -0,0 +1,13 @@
*.o
bitstr-test
amr-encode-test
amr-decode-test
core
.depend
auxlib.c
codeclib.c
fix_frame_channel_layout.h
loglib.c
resample.c
rtplib.c
str.c

@ -0,0 +1,111 @@
import os
import ycm_core
from clang_helpers import PrepareClangFlags
# Set this to the absolute path to the folder (NOT the file!) containing the
# compile_commands.json file to use that instead of 'flags'. See here for
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
# Most projects will NOT need to set this to anything; you can just change the
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
compilation_database_folder = ''
# These are the compilation flags that will be used in case there's no
# compilation database set.
flags = [
'-g',
'-Wall',
'-pthread',
'-fno-strict-aliasing',
'-I/usr/include/glib-2.0',
'-I/usr/lib/x86_64-linux-gnu/glib-2.0/include',
'-I/usr/include/json-glib-1.0',
'-pthread',
'-I../kernel-module/',
'-I../lib/',
'-D_GNU_SOURCE',
'-D__DEBUG=1',
'-D__YCM=1',
'-DRTPENGINE_VERSION="dummy"',
'-DRE_PLUGIN_DIR="/usr/lib/rtpengine"',
'-DWITH_IPTABLES_OPTION',
'-DWITH_TRANSCODING',
'-DHAVE_BCG729',
'-O2',
'-fstack-protector',
'--param=ssp-buffer-size=4',
'-Wformat',
'-Werror=format-security',
'-D_FORTIFY_SOURCE=2',
# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't
# know which language to use when compiling headers. So it will guess.
# Badly. So C++ headers will be compiled as C headers.
# You don't want that so ALWAYS specify
# a "-std=<something>".
# For a C project, you would set this to something like 'c99' instead of
# 'c++11'.
'-std=c99',
# ...and the same thing goes for the magic -x option which specifies the
# language that the files to be compiled are written in. This is mostly
# relevant for c++ headers.
# For a C project, you would set this to 'c' instead of 'c++'.
'-x',
'c',
]
if compilation_database_folder:
database = ycm_core.CompilationDatabase(compilation_database_folder)
else:
database = None
def DirectoryOfThisScript():
return os.path.dirname(os.path.abspath(__file__))
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
if not working_directory:
return flags
new_flags = []
make_next_absolute = False
path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
for flag in flags:
new_flag = flag
if make_next_absolute:
make_next_absolute = False
if not flag.startswith('/'):
new_flag = os.path.join(working_directory, flag)
for path_flag in path_flags:
if flag == path_flag:
make_next_absolute = True
break
if flag.startswith(path_flag):
path = flag[len(path_flag):]
new_flag = path_flag + os.path.join(working_directory, path)
break
if new_flag:
new_flags.append(new_flag)
return new_flags
def FlagsForFile(filename):
if database:
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
# python list, but a "list-like" StringVec object
compilation_info = database.GetCompilationInfoForFile(filename)
final_flags = PrepareClangFlags(
MakeRelativePathsInFlagsAbsolute(
compilation_info.compiler_flags_,
compilation_info.compiler_working_dir_),
filename)
else:
relative_to = DirectoryOfThisScript()
final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
return {
'flags': final_flags,
'do_cache': True
}

@ -0,0 +1,62 @@
TARGET= unit-tests
with_transcoding ?= yes
CFLAGS= -g -Wall -pthread -fno-strict-aliasing
CFLAGS+= -std=c99
CFLAGS+= $(shell pkg-config --cflags glib-2.0)
CFLAGS+= $(shell pkg-config --cflags gthread-2.0)
CFLAGS+= $(shell pkg-config --cflags openssl)
CFLAGS+= -I. -I../lib/
CFLAGS+= -D_GNU_SOURCE
ifeq ($(with_transcoding),yes)
CFLAGS+= $(shell pkg-config --cflags libavcodec)
CFLAGS+= $(shell pkg-config --cflags libavformat)
CFLAGS+= $(shell pkg-config --cflags libavutil)
CFLAGS+= $(shell pkg-config --cflags libswresample)
CFLAGS+= $(shell pkg-config --cflags libavfilter)
CFLAGS+= -DWITH_TRANSCODING
else
CFLAGS+= -DWITHOUT_CODECLIB
endif
LDFLAGS+= $(shell pkg-config --libs glib-2.0)
LDFLAGS+= $(shell pkg-config --libs gthread-2.0)
LDFLAGS+= $(shell pkg-config --libs libcrypto)
LDFLAGS+= $(shell pkg-config --libs openssl)
ifeq ($(with_transcoding),yes)
LDFLAGS+= $(shell pkg-config --libs libavcodec)
LDFLAGS+= $(shell pkg-config --libs libavformat)
LDFLAGS+= $(shell pkg-config --libs libavutil)
LDFLAGS+= $(shell pkg-config --libs libswresample)
LDFLAGS+= $(shell pkg-config --libs libavfilter)
endif
SRCS= bitstr-test.c amr-decode-test.c amr-encode-test.c
LIBSRCS= loglib.c auxlib.c str.c rtplib.c
ifeq ($(with_transcoding),yes)
LIBSRCS+= codeclib.c resample.c
endif
OBJS= $(SRCS:.c=.o) $(LIBSRCS:.c=.o)
include ../lib/common.Makefile
include .depend
.PHONY: unit-tests
TESTS= bitstr-test
ifeq ($(with_transcoding),yes)
TESTS+= amr-decode-test amr-encode-test
endif
ADD_CLEAN= $(TESTS)
unit-tests: $(TESTS)
for x in $(TESTS); do echo testing: $$x; ./$$x || exit 1; done
bitstr-test: bitstr-test.o
amr-decode-test: amr-decode-test.o codeclib.o str.o auxlib.o resample.o rtplib.o loglib.o
amr-encode-test: amr-encode-test.o codeclib.o str.o auxlib.o resample.o rtplib.o loglib.o

@ -0,0 +1,106 @@
#include "codeclib.h"
#include "str.h"
#include <assert.h>
static void hexdump(const unsigned char *buf, int len) {
for (int i = 0; i < len; i++)
printf("%02x", buf[i]);
printf("\n");
}
static int frame_cb(decoder_t *dec, AVFrame *frame, void *u1, void *u2) {
char **expect = u1;
int *expect_len = u2;
assert(expect);
assert(expect_len);
assert(*expect);
if (*expect_len != frame->linesize[0]
|| memcmp(frame->data[0], *expect, *expect_len))
{
printf(
"packet content mismatch\n"
"expected %i bytes, received %i bytes\n"
"expected:\n",
*expect_len, frame->linesize[0]);
hexdump((unsigned char *) *expect, *expect_len);
printf("received:\n");
hexdump((unsigned char *) frame->data[0], frame->linesize[0]);
exit(1);
}
*expect = NULL;
*expect_len = 0;
return 0;
}
static void do_test_amr_xx(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len,
char *codec, int clockrate)
{
printf("running test %s:%i\n", file, line);
str codec_name;
str_init(&codec_name, codec);
const codec_def_t *def = codec_find(&codec_name, MT_AUDIO);
assert(def);
if (!def->support_encoding || !def->support_decoding) {
printf("AMR not fully supported - skipping test\n");
exit(0);
}
const format_t fmt = { .clockrate = clockrate, .channels = 1, .format = AV_SAMPLE_FMT_S16};
str fmtp_str, *fmtp = NULL;
if (fmtp_s) {
str_init(&fmtp_str, fmtp_s);
fmtp = &fmtp_str;
}
decoder_t *d = decoder_new_fmtp(def, clockrate, 1, &fmt, fmtp);
assert(d);
const str data = { data_s, data_len };
int ret = decoder_input_data(d, &data, 1, frame_cb, &expect_s, &expect_len);
assert(!ret);
assert(expect_s == NULL);
decoder_close(d);
printf("test ok: %s:%i\n", file, line);
}
static void do_test_amr_wb(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len)
{
do_test_amr_xx(file, line, fmtp_s, data_s, data_len, expect_s, expect_len,
"AMR-WB", 16000);
}
static void do_test_amr_nb(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len)
{
do_test_amr_xx(file, line, fmtp_s, data_s, data_len, expect_s, expect_len,
"AMR", 8000);
}
#define do_test_wb(in, out, fmt) \
do_test_amr_wb(__FILE__, __LINE__, fmt, in, sizeof(in)-1, out, sizeof(out)-1)
#define do_test_nb(in, out, fmt) \
do_test_amr_nb(__FILE__, __LINE__, fmt, in, sizeof(in)-1, out, sizeof(out)-1)
int main() {
codeclib_init(0);
do_test_wb(
"\xf0\x44\xf1\x46\x18\x1d\xd1\x57\x23\x13\x42\xf0\x00\x0c\x50\x33\xdd\xff\x0b\x99\x89\x2c\x68\x52\xf8\xf8\xd9\x59\x16\xd7\x45\xe7\x01\xec\x1f\xfe\x5b\xc6\xf9\x01\xa4\xb5\xe0\x6c\x91\x41\xfe\x52\x2c\xce\x44\xbb\x5a\xdf\x76\x29\xf8\xdb\xca\x18\xd6\x50",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xff\xff\x02\x00\xff\xff\xff\xff\x02\x00\xfd\xff\x03\x00\x00\x00\xfd\xff\x04\x00\xfc\xff\x02\x00\x01\x00\xfd\xff\x03\x00\xfe\xff\x01\x00\x01\x00\xff\xff\x01\x00\xff\xff\x01\x00\xff\xff\x00\x00\x01\x00\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\xfe\xff\x02\x00\xff\xff\xff\xff\x03\x00\xfd\xff\x03\x00\xff\xff\xff\xff\x03\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x04\x00\xfe\xff\xfd\xff\x00\x00\x02\x00\xfe\xff\xf8\xff\x01\x00\x04\x00\xff\xff\xff\xff\xfc\xff\x06\x00\x00\x00\xf8\xff\x11\x00\x09\x00\x06\x00\x3f\x00\x37\x00\xf9\xff\x11\x00\x4e\x00\x34\x00\xf4\xff\x17\x00\x5d\x00\x31\x00\xe0\xff\x0b\x00\x71\x00\x42\x00\xd3\xff\x09\x00\x74\x00\x3c\x00\xc8\xff\x03\x00\x78\x00\x35\x00\xbc\xff\xff\xff\x7a\x00\x2e\x00\xb0\xff\x00\x00\x77\x00\x26\x00\xaa\xff\xfc\xff\x78\x00\x1c\x00\xa3\xff\xfe\xff\x72\x00\x14\x00\xa0\xff\xfc\xff\x6f\x00\x09\x00\x8e\xff\xfc\xff\x72\x00\xff\xff\x89\xff\xff\xff\x7e\x00\xfe\xff\x7b\xff\x19\x00\xa9\x00\xfa\xff\x62\xff\x14\x00\xae\x00\xf5\xff\x54\xff\x16\x00\xb6\x00\xe8\xff\x3f\xff\x0b\x00\xb9\x00\xee\xff\x34\xff\xfd\xff\xb8\x00\xe9\xff\x2d\xff\x00\x00\xb8\x00\xe4\xff\x2c\xff\xff\xff\xb9\x00\xdf\xff\x25\xff\xff\xff\xb2\x00\xda\xff\x28\xff\xfc\xff\xae\x00\xd6\xff\x2a\xff\xff\xff\xa5\x00\xd8\xff\x30\xff\xfc\xff\xa1\x00\xd5\xff\x35\xff\xf9\xff\x97\x00\xd4\xff\x37\xff\xfa\xff\x92\x00\xcd\xff\x38\xff\xfe\xff\x8e\x00\xcb\xff\x3e\xff\xfe\xff\x88\x00\xcc\xff\x40\xff\xfa\xff\x89\x00\xcf\xff\x41\xff\xfa\xff\x87\x00\xd0\xff\x44\xff\xfa\xff\x89\x00\xd6\xff\x48\xff\xf9\xff\x88\x00\xdd\xff\x4d\xff\xf2\xff\x81\x00\xde\xff\x54\xff\xf4\xff\x7b\x00\xde\xff\x5c\xff\xf6\xff\x73\x00\xe0\xff\x65\xff\xf6\xff\x6d\x00\xe0\xff\x6f\xff\xf7\xff\x63\x00\xe0\xff\x78\xff\xf7\xff\x5d\x00\xde\xff\x76\xff\xf9\xff\x60\x00\xdf\xff\x7f\xff\xfb\xff\x5c\x00\xe8\xff\x85\xff\xfb\xff\x60\x00\xea\xff\x87\xff\xfe\xff\x63\x00\xee\xff\x8b\xff\x00\x00\x64\x00\xf3\xff\x8d\xff\xfe\xff\x66\x00\xf7\xff\x8f\xff\xfd\xff\x68\x00\xf9\xff\x8c\xff\xfd\xff\x6d\x00\xfc\xff\x8c\xff\xfd\xff\x71\x00\xff\xff\x89\xff\xfe\xff\x75\x00\x02\x00\x88\xff\xfc\xff\x78\x00\x03\x00\x87\xff\xfd\xff\x7b\x00\x03\x00\x86\xff\x00\x00\x7e\x00\x03\x00\x84\xff\xfe\xff\x81\x00\x07\x00\x82\xff\x01\x00\x84\x00\x03\x00\x82\xff\x05\x00\x88\x00\x05\x00\x81\xff\x04\x00\x88\x00\x05\x00\x80\xff\x05\x00\x8a\x00\x05\x00",
"octet-align=1");
do_test_wb(
"\xf4\x7c\x51\x86\x07\x74\x55\xc8\xc4\xd0\xbc\x00\x03\x14\x0c\xf7\x7f\xc2\xe6\x62\x4b\x1a\x14\xbe\x3e\x36\x56\x45\xb5\xd1\x79\xc0\x7b\x07\xff\x96\xf1\xbe\x40\x69\x2d\x78\x1b\x24\x50\x7f\x94\x8b\x33\x91\x2e\xd6\xb7\xdd\x8a\x7e\x36\xf2\x86\x35\x94",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xff\xff\x02\x00\xff\xff\xff\xff\x02\x00\xfd\xff\x03\x00\x00\x00\xfd\xff\x04\x00\xfc\xff\x02\x00\x01\x00\xfd\xff\x03\x00\xfe\xff\x01\x00\x01\x00\xff\xff\x01\x00\xff\xff\x01\x00\xff\xff\x00\x00\x01\x00\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\xfe\xff\x02\x00\xff\xff\xff\xff\x03\x00\xfd\xff\x03\x00\xff\xff\xff\xff\x03\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x04\x00\xfe\xff\xfd\xff\x00\x00\x02\x00\xfe\xff\xf8\xff\x01\x00\x04\x00\xff\xff\xff\xff\xfc\xff\x06\x00\x00\x00\xf8\xff\x11\x00\x09\x00\x06\x00\x3f\x00\x37\x00\xf9\xff\x11\x00\x4e\x00\x34\x00\xf4\xff\x17\x00\x5d\x00\x31\x00\xe0\xff\x0b\x00\x71\x00\x42\x00\xd3\xff\x09\x00\x74\x00\x3c\x00\xc8\xff\x03\x00\x78\x00\x35\x00\xbc\xff\xff\xff\x7a\x00\x2e\x00\xb0\xff\x00\x00\x77\x00\x26\x00\xaa\xff\xfc\xff\x78\x00\x1c\x00\xa3\xff\xfe\xff\x72\x00\x14\x00\xa0\xff\xfc\xff\x6f\x00\x09\x00\x8e\xff\xfc\xff\x72\x00\xff\xff\x89\xff\xff\xff\x7e\x00\xfe\xff\x7b\xff\x19\x00\xa9\x00\xfa\xff\x62\xff\x14\x00\xae\x00\xf5\xff\x54\xff\x16\x00\xb6\x00\xe8\xff\x3f\xff\x0b\x00\xb9\x00\xee\xff\x34\xff\xfd\xff\xb8\x00\xe9\xff\x2d\xff\x00\x00\xb8\x00\xe4\xff\x2c\xff\xff\xff\xb9\x00\xdf\xff\x25\xff\xff\xff\xb2\x00\xda\xff\x28\xff\xfc\xff\xae\x00\xd6\xff\x2a\xff\xff\xff\xa5\x00\xd8\xff\x30\xff\xfc\xff\xa1\x00\xd5\xff\x35\xff\xf9\xff\x97\x00\xd4\xff\x37\xff\xfa\xff\x92\x00\xcd\xff\x38\xff\xfe\xff\x8e\x00\xcb\xff\x3e\xff\xfe\xff\x88\x00\xcc\xff\x40\xff\xfa\xff\x89\x00\xcf\xff\x41\xff\xfa\xff\x87\x00\xd0\xff\x44\xff\xfa\xff\x89\x00\xd6\xff\x48\xff\xf9\xff\x88\x00\xdd\xff\x4d\xff\xf2\xff\x81\x00\xde\xff\x54\xff\xf4\xff\x7b\x00\xde\xff\x5c\xff\xf6\xff\x73\x00\xe0\xff\x65\xff\xf6\xff\x6d\x00\xe0\xff\x6f\xff\xf7\xff\x63\x00\xe0\xff\x78\xff\xf7\xff\x5d\x00\xde\xff\x76\xff\xf9\xff\x60\x00\xdf\xff\x7f\xff\xfb\xff\x5c\x00\xe8\xff\x85\xff\xfb\xff\x60\x00\xea\xff\x87\xff\xfe\xff\x63\x00\xee\xff\x8b\xff\x00\x00\x64\x00\xf3\xff\x8d\xff\xfe\xff\x66\x00\xf7\xff\x8f\xff\xfd\xff\x68\x00\xf9\xff\x8c\xff\xfd\xff\x6d\x00\xfc\xff\x8c\xff\xfd\xff\x71\x00\xff\xff\x89\xff\xfe\xff\x75\x00\x02\x00\x88\xff\xfc\xff\x78\x00\x03\x00\x87\xff\xfd\xff\x7b\x00\x03\x00\x86\xff\x00\x00\x7e\x00\x03\x00\x84\xff\xfe\xff\x81\x00\x07\x00\x82\xff\x01\x00\x84\x00\x03\x00\x82\xff\x05\x00\x88\x00\x05\x00\x81\xff\x04\x00\x88\x00\x05\x00\x80\xff\x05\x00\x8a\x00\x05\x00",
NULL);
do_test_wb(
"\xf4\x7c\x51\x86\x07\x74\x55\xc8\xc4\xd0\xbc\x00\x03\x14\x0c\xf7\x7f\xc2\xe6\x62\x4b\x1a\x14\xbe\x3e\x36\x56\x45\xb5\xd1\x79\xc0\x7b\x07\xff\x96\xf1\xbe\x40\x69\x2d\x78\x1b\x24\x50\x7f\x94\x8b\x33\x91\x2e\xd6\xb7\xdd\x8a\x7e\x36\xf2\x86\x35\x94",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xff\xff\x02\x00\xff\xff\xff\xff\x02\x00\xfd\xff\x03\x00\x00\x00\xfd\xff\x04\x00\xfc\xff\x02\x00\x01\x00\xfd\xff\x03\x00\xfe\xff\x01\x00\x01\x00\xff\xff\x01\x00\xff\xff\x01\x00\xff\xff\x00\x00\x01\x00\xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\x01\x00\xfe\xff\x02\x00\xff\xff\xff\xff\x03\x00\xfd\xff\x03\x00\xff\xff\xff\xff\x03\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x02\x00\xfe\xff\x01\x00\x00\x00\xff\xff\x04\x00\xfe\xff\xfd\xff\x00\x00\x02\x00\xfe\xff\xf8\xff\x01\x00\x04\x00\xff\xff\xff\xff\xfc\xff\x06\x00\x00\x00\xf8\xff\x11\x00\x09\x00\x06\x00\x3f\x00\x37\x00\xf9\xff\x11\x00\x4e\x00\x34\x00\xf4\xff\x17\x00\x5d\x00\x31\x00\xe0\xff\x0b\x00\x71\x00\x42\x00\xd3\xff\x09\x00\x74\x00\x3c\x00\xc8\xff\x03\x00\x78\x00\x35\x00\xbc\xff\xff\xff\x7a\x00\x2e\x00\xb0\xff\x00\x00\x77\x00\x26\x00\xaa\xff\xfc\xff\x78\x00\x1c\x00\xa3\xff\xfe\xff\x72\x00\x14\x00\xa0\xff\xfc\xff\x6f\x00\x09\x00\x8e\xff\xfc\xff\x72\x00\xff\xff\x89\xff\xff\xff\x7e\x00\xfe\xff\x7b\xff\x19\x00\xa9\x00\xfa\xff\x62\xff\x14\x00\xae\x00\xf5\xff\x54\xff\x16\x00\xb6\x00\xe8\xff\x3f\xff\x0b\x00\xb9\x00\xee\xff\x34\xff\xfd\xff\xb8\x00\xe9\xff\x2d\xff\x00\x00\xb8\x00\xe4\xff\x2c\xff\xff\xff\xb9\x00\xdf\xff\x25\xff\xff\xff\xb2\x00\xda\xff\x28\xff\xfc\xff\xae\x00\xd6\xff\x2a\xff\xff\xff\xa5\x00\xd8\xff\x30\xff\xfc\xff\xa1\x00\xd5\xff\x35\xff\xf9\xff\x97\x00\xd4\xff\x37\xff\xfa\xff\x92\x00\xcd\xff\x38\xff\xfe\xff\x8e\x00\xcb\xff\x3e\xff\xfe\xff\x88\x00\xcc\xff\x40\xff\xfa\xff\x89\x00\xcf\xff\x41\xff\xfa\xff\x87\x00\xd0\xff\x44\xff\xfa\xff\x89\x00\xd6\xff\x48\xff\xf9\xff\x88\x00\xdd\xff\x4d\xff\xf2\xff\x81\x00\xde\xff\x54\xff\xf4\xff\x7b\x00\xde\xff\x5c\xff\xf6\xff\x73\x00\xe0\xff\x65\xff\xf6\xff\x6d\x00\xe0\xff\x6f\xff\xf7\xff\x63\x00\xe0\xff\x78\xff\xf7\xff\x5d\x00\xde\xff\x76\xff\xf9\xff\x60\x00\xdf\xff\x7f\xff\xfb\xff\x5c\x00\xe8\xff\x85\xff\xfb\xff\x60\x00\xea\xff\x87\xff\xfe\xff\x63\x00\xee\xff\x8b\xff\x00\x00\x64\x00\xf3\xff\x8d\xff\xfe\xff\x66\x00\xf7\xff\x8f\xff\xfd\xff\x68\x00\xf9\xff\x8c\xff\xfd\xff\x6d\x00\xfc\xff\x8c\xff\xfd\xff\x71\x00\xff\xff\x89\xff\xfe\xff\x75\x00\x02\x00\x88\xff\xfc\xff\x78\x00\x03\x00\x87\xff\xfd\xff\x7b\x00\x03\x00\x86\xff\x00\x00\x7e\x00\x03\x00\x84\xff\xfe\xff\x81\x00\x07\x00\x82\xff\x01\x00\x84\x00\x03\x00\x82\xff\x05\x00\x88\x00\x05\x00\x81\xff\x04\x00\x88\x00\x05\x00\x80\xff\x05\x00\x8a\x00\x05\x00",
"");
do_test_nb(
"\xf0\x3c\x53\xff\x3a\xe8\x30\x41\xa5\xa8\xa4\x1d\x2f\xf2\x03\x60\x35\xc0\x00\x07\xc5\x53\xf4\xbc\x98\x00\x01\x14\x2f\xf0\x00\x0f\x70",
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xff\xf8\xff\x10\x00\x00\x00\xe8\xff\xf8\xff\x28\x00\x00\x00\xc8\xff\x00\x00\x38\x00\xf8\xff\xb0\xff\x08\x00\x48\x00\xf0\xff\xa8\xff\x08\x00\x60\x00\xf8\xff\x98\xff\x08\x00\x88\x00\xf0\xff\x88\xff\x10\x00\x88\x00\xe8\xff\x70\xff\x18\x00\x80\x00\xd8\xff\x70\xff\x08\x00\x78\x00\xd8\xff\x88\xff\x08\x00\x78\x00\xe8\xff\x90\xff\x10\x00\x70\x00\xe0\xff\x90\xff\x08\x00\x68\x00\xf8\xff\x88\xff\x00\x00\x80\x00\xf8\xff\x88\xff\x00\x00\x80\x00\xf8\xff\x78\xff\x08\x00\x80\x00\xe8\xff\x78\xff\x08\x00\x78\x00\xe0\xff\x88\xff\x10\x00\x70\x00\xe8\xff\x90\xff\x10\x00\x68\x00\xe0\xff\x98\xff\x08\x00\x70\x00\xe8\xff\xa8\xff\xf8\xff\x70\x00\xf0\xff\x98\xff\xf8\xff\x68\x00\x00\x00\x80\xff\xf8\xff\x68\x00\xf8\xff\x90\xff\x00\x00\x70\x00\xf8\xff\x90\xff\x00\x00\x78\x00\xf0\xff\x88\xff\x00\x00\x80\x00\xf8\xff\x80\xff\x00\x00\x88\x00\xf8\xff\x80\xff\xf8\xff\x88\x00\xf8\xff\x70\xff\x00\x00\x80\x00\xf0\xff\x80\xff\xf8\xff\x80\x00\xe8\xff\x80\xff\xf0\xff\x88\x00",
"octet-align=1");
return 0;
}

@ -0,0 +1,147 @@
#include "codeclib.h"
#include "str.h"
#include <assert.h>
static void hexdump(const unsigned char *buf, int len) {
for (int i = 0; i < len; i++)
printf("%02x", buf[i]);
printf("\n");
}
static int dec_cb(encoder_t *e, void *u1, void *u2) {
char **expect = u1;
int *expect_len = u2;
assert(expect);
assert(expect_len);
assert(*expect);
GString *buf = g_string_new("");
int plen = 256;
char payload[plen];
str inout = { payload, plen };
e->def->packetizer(&e->avpkt, buf, &inout, e);
if (inout.len != *expect_len
|| memcmp(inout.s, *expect, *expect_len))
{
printf(
"packet content mismatch\n"
"expected %i bytes, received %i bytes\n"
"expected:\n",
*expect_len, inout.len);
hexdump((unsigned char *) *expect, *expect_len);
printf("received:\n");
hexdump((unsigned char *) inout.s, inout.len);
exit(1);
}
*expect = NULL;
*expect_len = 0;
g_string_free(buf, TRUE);
return 0;
}
static void do_test_amr_xx(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len,
int bitrate, char *codec, int clockrate)
{
printf("running test %s:%i\n", file, line);
str codec_name;
str_init(&codec_name, codec);
const codec_def_t *def = codec_find(&codec_name, MT_AUDIO);
assert(def);
if (!def->support_encoding || !def->support_decoding) {
printf("AMR not fully supported - skipping test\n");
exit(0);
}
const format_t fmt = { .clockrate = clockrate, .channels = 1, .format = 0 };
str fmtp_str, *fmtp = NULL;
char *fmtp_buf = NULL;
if (fmtp_s) {
fmtp_buf = strdup(fmtp_s);
str_init(&fmtp_str, fmtp_buf);
fmtp = &fmtp_str;
}
encoder_t *e = encoder_new();
assert(e);
format_t actual_fmt;
int ret = encoder_config_fmtp(e, def, bitrate, 20, &fmt, &actual_fmt, fmtp);
assert(actual_fmt.clockrate == clockrate);
assert(actual_fmt.channels == 1);
assert(actual_fmt.format == AV_SAMPLE_FMT_S16);
AVFrame *frame = av_frame_alloc();
assert(frame);
frame->nb_samples = 20 * clockrate / 1000;
frame->format = actual_fmt.format;
frame->sample_rate = actual_fmt.clockrate;
frame->channel_layout = av_get_default_channel_layout(actual_fmt.channels);
ret = av_frame_get_buffer(frame, 0);
assert(ret >= 0);
assert(data_len == frame->nb_samples * 2);
memcpy(frame->data[0], data_s, data_len);
ret = encoder_input_data(e, frame, dec_cb, &expect_s, &expect_len);
assert(!ret);
assert(expect_s == NULL);
encoder_free(e);
free(fmtp_buf);
printf("test ok: %s:%i\n", file, line);
}
static void do_test_amr_wb(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len,
int bitrate)
{
do_test_amr_xx(file, line, fmtp_s, data_s, data_len, expect_s, expect_len, bitrate,
"AMR-WB", 16000);
}
static void do_test_amr_nb(const char *file, int line,
char *fmtp_s, char *data_s, int data_len, char *expect_s, int expect_len,
int bitrate)
{
do_test_amr_xx(file, line, fmtp_s, data_s, data_len, expect_s, expect_len, bitrate,
"AMR", 8000);
}
#define do_test_wb(in, out, fmt, bitrate) \
do_test_amr_wb(__FILE__, __LINE__, fmt, in, sizeof(in)-1, out, sizeof(out)-1, bitrate)
#define do_test_nb(in, out, fmt, bitrate) \
do_test_amr_nb(__FILE__, __LINE__, fmt, in, sizeof(in)-1, out, sizeof(out)-1, bitrate)
#define test_320_samples_16_bits \
"\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01"
#define test_160_samples_16_bits \
"\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01\x00\x00\x01\x00\x01\x00\x01\x01"
int main() {
codeclib_init(0);
do_test_wb(
test_320_samples_16_bits,
"\xf0\x44\xf1\x46\x18\x1d\xd1\x57\x23\x13\x42\xf0\x00\x0c\x50\x33\xdd\xff\x0b\x99\x89\x2c\x68\x52\xf8\xf8\xd9\x59\x16\xd7\x45\xe7\x01\xec\x1f\xfe\x5b\xc6\xf9\x01\xa4\xb5\xe0\x6c\x91\x41\xfe\x52\x2c\xce\x44\xbb\x5a\xdf\x76\x29\xf8\xdb\xca\x18\xd6\x50",
"octet-align=1",
23850);
do_test_wb(
test_320_samples_16_bits,
"\xf0\x00\x44\xf1\x46\x18\x1d\xd1\x57\x23\x13\x42\xf0\x00\x0c\x50\x33\xdd\xff\x0b\x99\x89\x2c\x68\x52\xf8\xf8\xd9\x59\x16\xd7\x45\xe7\x01\xec\x1f\xfe\x5b\xc6\xf9\x01\xa4\xb5\xe0\x6c\x91\x41\xfe\x52\x2c\xce\x44\xbb\x5a\xdf\x76\x29\xf8\xdb\xca\x18\xd6\x50",
"octet-align=1;interleaving=4",
23850);
do_test_wb(
test_320_samples_16_bits,
"\xf4\x7c\x51\x86\x07\x74\x55\xc8\xc4\xd0\xbc\x00\x03\x14\x0c\xf7\x7f\xc2\xe6\x62\x4b\x1a\x14\xbe\x3e\x36\x56\x45\xb5\xd1\x79\xc0\x7b\x07\xff\x96\xf1\xbe\x40\x69\x2d\x78\x1b\x24\x50\x7f\x94\x8b\x33\x91\x2e\xd6\xb7\xdd\x8a\x7e\x36\xf2\x86\x35\x94",
NULL,
23850);
do_test_nb(
test_160_samples_16_bits,
"\xf0\x3c\x53\xff\x3a\xe8\x30\x41\xa5\xa8\xa4\x1d\x2f\xf2\x03\x60\x35\xc0\x00\x07\xc5\x53\xf4\xbc\x98\x00\x01\x14\x2f\xf0\x00\x0f\x70",
"octet-align=1",
12200);
return 0;
}

@ -0,0 +1,204 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "bitstr.h"
#include "str.h"
#define do_test_ret(retval, args...) do { \
int r = do_test(args); \
if (r != retval) \
err("didn't run all tests!\n"); \
} while (0)
#define test1(input, shift_len, output, result) \
do_test_ret(1, input, sizeof(input)-1, __FILE__, __LINE__, shift_len, output, sizeof(output)-1, \
result, 0)
#define test2(input, shift_len1, output1, result1, shift_len2, output2, result2) \
do_test_ret(2, input, sizeof(input)-1, __FILE__, __LINE__, \
shift_len1, output1, sizeof(output1)-1, result1, \
shift_len2, output2, sizeof(output2)-1, result2, \
0)
#define test3(input, \
shift_len1, output1, result1, \
shift_len2, output2, result2, \
shift_len3, output3, result3) \
do_test_ret(3, input, sizeof(input)-1, __FILE__, __LINE__, \
shift_len1, output1, sizeof(output1)-1, result1, \
shift_len2, output2, sizeof(output2)-1, result2, \
shift_len3, output3, sizeof(output3)-1, result3, \
0)
#define err(fmt...) do { \
fprintf(stderr, fmt); \
exit(1); \
} while (0)
int do_test(const char *input, unsigned int input_len,
const char *file, unsigned int line,
...)
{
char in_buf[input_len];
memcpy(in_buf, input, input_len);
str inp;
str_init_len(&inp, in_buf, input_len);
bitstr inp_bs;
bitstr_init(&inp_bs, &inp);
va_list ap;
va_start(ap, line);
int argc = 0;
while (1) {
unsigned int shift_len = va_arg(ap, unsigned int);
if (!shift_len)
break;
const char *output = va_arg(ap, const char *);
unsigned int output_len = va_arg(ap, unsigned int);
int result = va_arg(ap, int);
char out_buf[output_len+1];
str outp = STR_CONST_INIT_BUF(out_buf);
int ret;
if (output)
ret = bitstr_shift_ret(&inp_bs, shift_len, &outp);
else
ret = bitstr_shift(&inp_bs, shift_len);
if (ret != result)
err("ERROR return %i instead of %i (%s:%i arg %i)\n",
ret, result, file, line, argc);
if (ret == 0 && output) {
if (outp.len != output_len)
err("ERROR output len %i instead of %i (%s:%i arg %i)\n",
outp.len, output_len, file, line, argc);
if (memcmp(outp.s, output, output_len))
err("ERROR output string mismatch (%s:%i arg %i)\n",
file, line, argc);
}
// if (inp.len != remainder_len)
// err("ERROR remainder len %i instead of %i (%s:%i arg %i)\n",
// inp.len, remainder_len, file, line, argc);
printf("test ok: %s:%i arg %i\n", file, line, argc);
argc++;
}
return argc;
}
int main() {
test1("\x81", 8, "\x81", 0);
test2("\x81", 8, "\x81", 0, 1, "", -1);
test2("\x81", 8, "\x81", 0, 1, NULL, -1);
test1("\x81", 7, "\x80", 0);
test2("\x81", 7, "\x80", 0, 1, "\x80", 0);
test3("\x81", 7, "\x80", 0, 1, "\x80", 0, 1, "", -1);
test3("\x81", 7, "\x80", 0, 1, NULL, 0, 1, "", -1);
test3("\x81", 7, "\x80", 0, 1, "\x80", 0, 1, NULL, -1);
test3("\x81", 7, "\x80", 0, 1, NULL, 0, 1, NULL, -1);
test2("\x81", 7, "\x80", 0, 2, "", -1);
test2("\x81", 7, "\x80", 0, 2, NULL, -1);
test1("\x82", 7, "\x82", 0);
test2("\x82", 7, "\x82", 0, 1, "\x00", 0);
test2("\x82", 7, NULL, 0, 1, "\x00", 0);
test3("\x82", 7, "\x82", 0, 1, "\x00", 0, 1, "", -1);
test3("\x82", 7, "\x82", 0, 1, NULL, 0, 1, "", -1);
test3("\x82", 7, "\x82", 0, 1, "\x00", 0, 1, NULL, -1);
test3("\x82", 7, "\x82", 0, 1, NULL, 0, 1, NULL, -1);
test2("\x82", 7, "\x82", 0, 2, "", -1);
test2("\x82", 7, "\x82", 0, 2, NULL, -1);
test1("\x83", 7, "\x82", 0);
test2("\x83", 7, "\x82", 0, 1, "\x80", 0);
test2("\x83", 7, NULL, 0, 1, "\x80", 0);
test3("\x83", 7, "\x82", 0, 1, "\x80", 0, 1, "", -1);
test3("\x83", 7, "\x82", 0, 1, NULL, 0, 1, "", -1);
test2("\x83", 7, "\x82", 0, 2, "", -1);
test1("\x81", 1, "\x80", 0);
test2("\x81", 1, "\x80", 0, 7, "\x02", 0);
test3("\x81", 1, "\x80", 0, 7, "\x02", 0, 1, "", -1);
test3("\x81", 1, NULL, 0, 7, "\x02", 0, 1, "", -1);
test3("\x81", 1, "\x80", 0, 7, NULL, 0, 1, "", -1);
test3("\x81", 1, NULL, 0, 7, NULL, 0, 1, "", -1);
test1("\xff", 1, "\x80", 0);
test2("\xff", 1, "\x80", 0, 5, "\xf8", 0);
test3("\xff", 1, "\x80", 0, 5, "\xf8", 0, 2, "\xc0", 0);
test3("\xff", 1, NULL, 0, 5, "\xf8", 0, 2, "\xc0", 0);
test3("\xff", 1, "\x80", 0, 5, NULL, 0, 2, "\xc0", 0);
test3("\xff", 1, NULL, 0, 5, NULL, 0, 2, "\xc0", 0);
test3("\xff", 1, "\x80", 0, 5, "\xf8", 0, 3, "", -1);
test2("\xff", 1, "\x80", 0, 7, "\xfe", 0);
test3("\xff", 1, "\x80", 0, 7, "\xfe", 0, 1, "", -1);
test3("\xff", 1, NULL, 0, 7, "\xfe", 0, 1, "", -1);
test3("\xff", 1, "\x80", 0, 7, NULL, 0, 1, "", -1);
test3("\xff", 1, NULL, 0, 7, NULL, 0, 1, "", -1);
test1("J76x", 8, "J", 0);
test2("J76x", 8, "J", 0, 8, "7", 0);
test3("J76x", 8, "J", 0, 8, "7", 0, 7, "6", 0);
test3("J76x", 8, "J", 0, 8, "7", 0, 14, "6x", 0);
test3("J76x", 8, "J", 0, 8, "7", 0, 16, "6x", 0);
test3("J76x", 8, "J", 0, 8, "7", 0, 17, "", -1);
test2("J76x", 8, "J", 0, 12, "70", 0);
test3("J76x", 8, "J", 0, 12, "70", 0, 3, "`", 0);
test3("J76x", 8, "J", 0, 12, "70", 0, 6, "d", 0);
test3("J76x", 8, "J", 0, 12, "70", 0, 8, "g", 0);
test3("J76x", 8, "J", 0, 12, "70", 0, 12, "g\x80", 0);
test3("J76x", 8, NULL, 0, 12, "70", 0, 12, "g\x80", 0);
test3("J76x", 8, "J", 0, 12, NULL, 0, 12, "g\x80", 0);
test3("J76x", 8, NULL, 0, 12, NULL, 0, 12, "g\x80", 0);
test3("J76x", 8, "J", 0, 12, "70", 0, 13, "", -1);
test2("J76x", 8, "J", 0, 14, "74", 0);
test3("J76x", 8, "J", 0, 14, "74", 0, 5, "\x98", 0);
test3("J76x", 8, NULL, 0, 14, "74", 0, 5, "\x98", 0);
test3("J76x", 8, "J", 0, 14, NULL, 0, 5, "\x98", 0);
test3("J76x", 8, NULL, 0, 14, NULL, 0, 5, "\x98", 0);
test3("J76x", 8, "J", 0, 14, "74", 0, 8, "\x9e", 0);
test3("J76x", 8, NULL, 0, 14, "74", 0, 8, "\x9e", 0);
test3("J76x", 8, "J", 0, 14, NULL, 0, 8, "\x9e", 0);
test3("J76x", 8, NULL, 0, 14, NULL, 0, 8, "\x9e", 0);
test1("J76x", 12, "J0", 0);
test2("J76x", 12, "J0", 0, 3, "`", 0);
test3("J76x", 12, "J0", 0, 3, "`", 0, 3, "\x80", 0);
test3("J76x", 12, "J0", 0, 3, "`", 0, 6, "\x98", 0);
test2("J76x", 12, "J0", 0, 4, "p", 0);
test2("J76x", 12, "J0", 0, 4, "p", 0);
test3("J76x", 12, "J0", 0, 4, "p", 0, 3, "\x20", 0);
test3("J76x", 12, "J0", 0, 4, "p", 0, 6, "\x34", 0);
test2("J76x", 12, "J0", 0, 6, "p", 0);
test2("J76x", 12, "J0", 0, 6, "p", 0);
test3("J76x", 12, "J0", 0, 6, "p", 0, 3, "\xc0", 0);
test3("J76x", 12, "J0", 0, 6, "p", 0, 6, "\xd8", 0);
test2("J76x", 12, "J0", 0, 8, "s", 0);
test2("J76x", 12, "J0", 0, 8, "s", 0);
test3("J76x", 12, "J0", 0, 8, "s", 0, 3, "\x60", 0);
test3("J76x", 12, "J0", 0, 8, "s", 0, 6, "\x64", 0);
test2("J76x", 12, "J0", 0, 11, "s`", 0);
test2("J76x", 12, "J0", 0, 11, "s`", 0);
test3("J76x", 12, "J0", 0, 11, "s`", 0, 3, "\x20", 0);
test3("J76x", 12, "J0", 0, 11, "s`", 0, 6, "\x3c", 0);
test2("J76x", 12, "J0", 0, 18, "sg\x80", 0);
test2("J76x", 12, "J0", 0, 18, "sg\x80", 0);
test3("J76x", 12, "J0", 0, 18, "sg\x80", 0, 2, "\x00", 0);
test3("J76x", 12, "J0", 0, 18, NULL, 0, 2, "\x00", 0);
test3("J76x", 12, NULL, 0, 18, "sg\x80", 0, 2, "\x00", 0);
test3("J76x", 12, NULL, 0, 18, NULL, 0, 2, "\x00", 0);
test3("J76x", 12, "J0", 0, 18, "sg\x80", 0, 3, NULL, -1);
// non octet aligned AMR
test3("\xf0\xde\xc0\x81\xc0\x08\xa9\xbc\x06\x33\x53\x14\x69\xdd\x3d\x2e\xa9\x8f\x81\xee\x2e\x09\x08\x80\xca\x05\x1e\x91\x00\x10\x00\x00\xca\x05\x20\x91\x00\x10\x00\x00\xca\x05\x22\x91\x00\x10\x00\x00\xca\x05\x24\x91\x00\x10\x00\x00\xca\x05\x26\x91\x00\x10", 4, "\xf0", 0, 6, "\x0c", 0, 177, "\x7b\x02\x07\x00\x22\xa6\xf0\x18\xcd\x4c\x51\xa7\x74\xf4\xba\xa6\x3e\x07\xb8\xb8\x24\x22\x00", 0);
}

@ -0,0 +1,7 @@
#ifndef __LOG_H__
#define __LOG_H__
#include "loglib.h"
#define __ilog(prio, fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
#endif
Loading…
Cancel
Save