|
|
|
|
@ -361,7 +361,7 @@ static codec_def_t __codec_defs[] = {
|
|
|
|
|
.default_channels = 1,
|
|
|
|
|
.default_bitrate = 6700,
|
|
|
|
|
.default_ptime = 20,
|
|
|
|
|
.default_fmtp = "octet-align=1",
|
|
|
|
|
.default_fmtp = "octet-align=1;mode-change-capability=2",
|
|
|
|
|
.packetizer = packetizer_amr,
|
|
|
|
|
.bits_per_sample = 2, // max is 12200 / 8000 = 1.525 bits per sample, rounded up
|
|
|
|
|
.media_type = MT_AUDIO,
|
|
|
|
|
@ -378,7 +378,7 @@ static codec_def_t __codec_defs[] = {
|
|
|
|
|
.default_channels = 1,
|
|
|
|
|
.default_bitrate = 14250,
|
|
|
|
|
.default_ptime = 20,
|
|
|
|
|
.default_fmtp = "octet-align=1",
|
|
|
|
|
.default_fmtp = "octet-align=1;mode-change-capability=2",
|
|
|
|
|
.packetizer = packetizer_amr,
|
|
|
|
|
.bits_per_sample = 2, // max is 23850 / 16000 = 1.490625 bits per sample, rounded up
|
|
|
|
|
.media_type = MT_AUDIO,
|
|
|
|
|
@ -1626,7 +1626,12 @@ static void amr_set_encdec_options_cb(str *key, str *token, void *data) {
|
|
|
|
|
opts->amr.mode_set |= (1 << m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// XXX other options
|
|
|
|
|
else if (!str_cmp(key, "mode-change-period"))
|
|
|
|
|
opts->amr.mode_change_period = str_to_i(token, 0);
|
|
|
|
|
else if (!str_cmp(key, "mode-change-neighbor")) {
|
|
|
|
|
if (token->len == 1 && token->s[0] == '1')
|
|
|
|
|
opts->amr.mode_change_neighbor = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void amr_set_encdec_options(codec_options_t *opts, const str *fmtp, const codec_def_t *def) {
|
|
|
|
|
if (!strcmp(def->rtpname, "AMR")) {
|
|
|
|
|
@ -1873,6 +1878,9 @@ static void amr_encoder_mode_change(encoder_t *enc) {
|
|
|
|
|
if (!memcmp(&enc->codec_options.amr.cmr.cmr_in_ts,
|
|
|
|
|
&enc->u.avc.u.amr.cmr_in_ts, sizeof(struct timeval)))
|
|
|
|
|
return;
|
|
|
|
|
// mode change requested: check if this is allowed right now
|
|
|
|
|
if (enc->codec_options.amr.mode_change_period == 2 && (enc->u.avc.u.amr.pkt_seq & 1) != 0)
|
|
|
|
|
return;
|
|
|
|
|
unsigned int cmr = enc->codec_options.amr.cmr.cmr_in;
|
|
|
|
|
if (cmr >= AMR_FT_TYPES)
|
|
|
|
|
return;
|
|
|
|
|
@ -1882,10 +1890,43 @@ static void amr_encoder_mode_change(encoder_t *enc) {
|
|
|
|
|
int req_br = enc->codec_options.amr.bitrates[cmr];
|
|
|
|
|
if (!req_br)
|
|
|
|
|
return;
|
|
|
|
|
int cmr_done = 1;
|
|
|
|
|
if (enc->codec_options.amr.mode_change_neighbor) {
|
|
|
|
|
// handle non-neighbour mode changes
|
|
|
|
|
int cur_br = enc->u.avc.avcctx->bit_rate;
|
|
|
|
|
// step up or down from the requested bitrate towards the current one
|
|
|
|
|
int cmr_diff = (req_br > cur_br) ? -1 : 1;
|
|
|
|
|
int neigh_br = req_br;
|
|
|
|
|
int cmr_br = req_br;
|
|
|
|
|
while (1) {
|
|
|
|
|
// step up or down towards the current bitrate
|
|
|
|
|
cmr += cmr_diff;
|
|
|
|
|
// still in bounds?
|
|
|
|
|
if (cmr < 0 || cmr >= AMR_FT_TYPES)
|
|
|
|
|
break;
|
|
|
|
|
cmr_br = enc->codec_options.amr.bitrates[cmr];
|
|
|
|
|
if (cmr_br == cur_br)
|
|
|
|
|
break;
|
|
|
|
|
// allowed by mode set?
|
|
|
|
|
if (enc->codec_options.amr.mode_set) {
|
|
|
|
|
if (!(enc->codec_options.amr.mode_set & (1 << cmr)))
|
|
|
|
|
continue; // go to next mode
|
|
|
|
|
}
|
|
|
|
|
// valid bitrate - continue stepping
|
|
|
|
|
neigh_br = cmr_br;
|
|
|
|
|
}
|
|
|
|
|
// did we finish stepping or is there more to go?
|
|
|
|
|
if (neigh_br != req_br)
|
|
|
|
|
cmr_done = 0;
|
|
|
|
|
req_br = neigh_br; // set to this
|
|
|
|
|
}
|
|
|
|
|
enc->u.avc.avcctx->bit_rate = req_br;
|
|
|
|
|
if (cmr_done)
|
|
|
|
|
enc->u.avc.u.amr.cmr_in_ts = enc->codec_options.amr.cmr.cmr_in_ts;
|
|
|
|
|
}
|
|
|
|
|
static void amr_encoder_got_packet(encoder_t *enc) {
|
|
|
|
|
amr_encoder_mode_change(enc);
|
|
|
|
|
enc->u.avc.u.amr.pkt_seq++;
|
|
|
|
|
}
|
|
|
|
|
static int packetizer_amr(AVPacket *pkt, GString *buf, str *output, encoder_t *enc) {
|
|
|
|
|
assert(pkt->size >= 1);
|
|
|
|
|
|