|
|
@ -1650,12 +1650,17 @@ static void amr_set_dec_codec_options(str *key, str *value, void *data) { |
|
|
|
|
|
|
|
|
if (!str_cmp(key, "CMR-interval")) |
|
|
if (!str_cmp(key, "CMR-interval")) |
|
|
dec->codec_options.amr.cmr_interval = str_to_i(value, 0); |
|
|
dec->codec_options.amr.cmr_interval = str_to_i(value, 0); |
|
|
|
|
|
else if (!str_cmp(key, "mode-change-interval")) |
|
|
|
|
|
dec->codec_options.amr.mode_change_interval = str_to_i(value, 0); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
static void amr_set_enc_codec_options(str *key, str *value, void *data) { |
|
|
static void amr_set_enc_codec_options(str *key, str *value, void *data) { |
|
|
encoder_t *enc = data; |
|
|
encoder_t *enc = data; |
|
|
|
|
|
|
|
|
if (!str_cmp(key, "CMR-interval")) |
|
|
if (!str_cmp(key, "CMR-interval")) |
|
|
; // not an encoder optoin |
|
|
|
|
|
|
|
|
; // not an encoder option |
|
|
|
|
|
else if (!str_cmp(key, "mode-change-interval")) |
|
|
|
|
|
; // not an encoder option |
|
|
else { |
|
|
else { |
|
|
// our string might not be null terminated |
|
|
// our string might not be null terminated |
|
|
char *s = g_strdup_printf(STR_FORMAT, STR_FMT(key)); |
|
|
char *s = g_strdup_printf(STR_FORMAT, STR_FMT(key)); |
|
|
@ -1770,8 +1775,21 @@ static int amr_decoder_input(decoder_t *dec, const str *data, GQueue *out) { |
|
|
goto err; |
|
|
goto err; |
|
|
|
|
|
|
|
|
unsigned int cmr_int = cmr_chr[0] >> 4; |
|
|
unsigned int cmr_int = cmr_chr[0] >> 4; |
|
|
if (cmr_int != 15) |
|
|
|
|
|
|
|
|
if (cmr_int != 15) { |
|
|
decoder_event(dec, CE_AMR_CMR_RECV, GUINT_TO_POINTER(cmr_int)); |
|
|
decoder_event(dec, CE_AMR_CMR_RECV, GUINT_TO_POINTER(cmr_int)); |
|
|
|
|
|
dec->u.avc.u.amr.last_cmr = rtpe_now; |
|
|
|
|
|
} |
|
|
|
|
|
else if (dec->codec_options.amr.mode_change_interval) { |
|
|
|
|
|
// no CMR, check if we're due to do our own mode change |
|
|
|
|
|
if (!dec->u.avc.u.amr.last_cmr.tv_sec) // start tracking now |
|
|
|
|
|
dec->u.avc.u.amr.last_cmr = rtpe_now; |
|
|
|
|
|
else if (timeval_diff(&rtpe_now, &dec->u.avc.u.amr.last_cmr) |
|
|
|
|
|
>= dec->codec_options.amr.mode_change_interval * 1000) { |
|
|
|
|
|
// switch up if we can |
|
|
|
|
|
decoder_event(dec, CE_AMR_CMR_RECV, GUINT_TO_POINTER(0xffff)); |
|
|
|
|
|
dec->u.avc.u.amr.last_cmr = rtpe_now; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (dec->codec_options.amr.octet_aligned) { |
|
|
if (dec->codec_options.amr.octet_aligned) { |
|
|
if (bitstr_shift(&d, 4)) |
|
|
if (bitstr_shift(&d, 4)) |
|
|
@ -1874,6 +1892,41 @@ err: |
|
|
|
|
|
|
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
static unsigned int amr_encoder_find_next_mode(encoder_t *enc) { |
|
|
|
|
|
int mode = -1; |
|
|
|
|
|
for (int i = 0; i < AMR_FT_TYPES; i++) { |
|
|
|
|
|
int br = enc->codec_options.amr.bitrates[i]; |
|
|
|
|
|
if (!br) // end of list |
|
|
|
|
|
break; |
|
|
|
|
|
if (br == enc->u.avc.avcctx->bit_rate) { |
|
|
|
|
|
mode = i; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (mode == -1) |
|
|
|
|
|
return -1; |
|
|
|
|
|
int next_mode = mode + 1; |
|
|
|
|
|
// if modes are restricted, find the next one up |
|
|
|
|
|
if (enc->codec_options.amr.mode_set) { |
|
|
|
|
|
// is there anything? |
|
|
|
|
|
if ((1 << next_mode) > enc->codec_options.amr.mode_set) |
|
|
|
|
|
return -1; |
|
|
|
|
|
int next_up = -1; |
|
|
|
|
|
for (; next_mode < AMR_FT_TYPES; next_mode++) { |
|
|
|
|
|
if (!(enc->codec_options.amr.mode_set & (1 << next_mode))) |
|
|
|
|
|
continue; |
|
|
|
|
|
next_up = next_mode; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
if (next_up == -1) |
|
|
|
|
|
return -1; |
|
|
|
|
|
next_mode = next_up; |
|
|
|
|
|
} |
|
|
|
|
|
// valid mode? |
|
|
|
|
|
if (next_mode >= AMR_FT_TYPES || enc->codec_options.amr.bitrates[next_mode] == 0) |
|
|
|
|
|
return -1; |
|
|
|
|
|
return next_mode; |
|
|
|
|
|
} |
|
|
static void amr_encoder_mode_change(encoder_t *enc) { |
|
|
static void amr_encoder_mode_change(encoder_t *enc) { |
|
|
if (!memcmp(&enc->codec_options.amr.cmr.cmr_in_ts, |
|
|
if (!memcmp(&enc->codec_options.amr.cmr.cmr_in_ts, |
|
|
&enc->u.avc.u.amr.cmr_in_ts, sizeof(struct timeval))) |
|
|
&enc->u.avc.u.amr.cmr_in_ts, sizeof(struct timeval))) |
|
|
@ -1882,6 +1935,8 @@ static void amr_encoder_mode_change(encoder_t *enc) { |
|
|
if (enc->codec_options.amr.mode_change_period == 2 && (enc->u.avc.u.amr.pkt_seq & 1) != 0) |
|
|
if (enc->codec_options.amr.mode_change_period == 2 && (enc->u.avc.u.amr.pkt_seq & 1) != 0) |
|
|
return; |
|
|
return; |
|
|
unsigned int cmr = enc->codec_options.amr.cmr.cmr_in; |
|
|
unsigned int cmr = enc->codec_options.amr.cmr.cmr_in; |
|
|
|
|
|
if (cmr == 0xffff) |
|
|
|
|
|
cmr = amr_encoder_find_next_mode(enc); |
|
|
if (cmr >= AMR_FT_TYPES) |
|
|
if (cmr >= AMR_FT_TYPES) |
|
|
return; |
|
|
return; |
|
|
// ignore CMR for invalid modes |
|
|
// ignore CMR for invalid modes |
|
|
|