[FFmpeg-devel] [PATCH 1/3] avcodec: add siren audio decoder

James Almer jamrial at gmail.com
Wed Apr 4 18:12:02 EEST 2018


On 4/4/2018 11:09 AM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  libavcodec/Makefile     |   1 +
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   8 +
>  libavcodec/siren.c      | 847 ++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 858 insertions(+)
>  create mode 100644 libavcodec/siren.c

[...]

> +static av_cold int siren_init(AVCodecContext *avctx)
> +{
> +    SirenContext *s = avctx->priv_data;
> +    int i;
> +
> +    avctx->channels       = 1;
> +    avctx->channel_layout = AV_CH_LAYOUT_MONO;
> +    avctx->sample_fmt     = AV_SAMPLE_FMT_S16;
> +
> +    s->number_of_coefs = 320;
> +    s->rate_control_bits = 4;
> +    s->rate_control_possibilities = 16;
> +    s->checksum_bits = 0;
> +    s->esf_adjustment = 7;
> +    s->number_of_regions = 14;
> +    s->scale_factor = 1;
> +    s->bits_per_frame = avctx->sample_rate / 50;
> +    s->region_size = 20;
> +    s->dw1 = s->dw2 = s->dw3 = s->dw4 = 1;
> +
> +    for (i = 0; i < 64; i++) {
> +        float region_power = powf(10, (i - 24) * STEPSIZE);
> +
> +        s->standard_deviation[i] = sqrtf(region_power);
> +        s->deviation_inverse[i] = 1.f / s->standard_deviation[i];
> +    }
> +
> +    for (i = 0; i < 320; i++) {
> +        float angle = ((i + 0.5f) * M_PI_2) / 320.f;
> +        s->window[i] = sinf(angle);
> +    }
> +
> +    ff_fft_init(&s->fft_ctx, 10, 0);

Missing fft dependency in configure.

> +
> +    return 0;
> +}

[...]

> +
> +static int categorize_regions(int number_of_regions, int number_of_available_bits,
> +                              int *absolute_region_power_index, int *power_categories,
> +                              int *category_balance)
> +{
> +    int region, delta, i, temp;
> +    int expected_number_of_code_bits;
> +    int min, max;
> +    int offset,
> +        num_rate_control_possibilities,
> +        raw_value, raw_max_idx = 0, raw_min_idx = 0;
> +    int max_rate_categories[28];
> +    int min_rate_categories[28];
> +    int temp_category_balances[64];
> +    int *min_rate_ptr = NULL;
> +    int *max_rate_ptr = NULL;
> +
> +    if (number_of_regions == 14) {
> +        num_rate_control_possibilities = 16;
> +        if (number_of_available_bits > 320)
> +            number_of_available_bits =
> +                ((number_of_available_bits - 320) * 5 / 8) + 320;
> +    } else {
> +        num_rate_control_possibilities = 32;
> +        if (number_of_regions == 28 && number_of_available_bits > 640)
> +            number_of_available_bits =
> +                ((number_of_available_bits - 640) * 5 / 8) + 640;
> +    }
> +
> +    offset = -32;
> +    for (delta = 32; number_of_regions > 0 && delta > 0; delta /= 2) {
> +        expected_number_of_code_bits = 0;
> +        for (region = 0; region < number_of_regions; region++) {
> +            i = (delta + offset -
> +                 absolute_region_power_index[region]) >> 1;
> +            if (i > 7)
> +                i = 7;
> +            else if (i < 0)
> +                i = 0;

av_clip_uintp2()

> +
> +            power_categories[region] = i;
> +            expected_number_of_code_bits += expected_bits_table[i];
> +
> +        }
> +        if (expected_number_of_code_bits >= number_of_available_bits - 32)
> +            offset += delta;
> +    }
> +
> +    expected_number_of_code_bits = 0;
> +    for (region = 0; region < number_of_regions; region++) {
> +        i = (offset - absolute_region_power_index[region]) >> 1;
> +        if (i > 7)
> +            i = 7;
> +        else if (i < 0)
> +            i = 0;

Same.

> +        max_rate_categories[region] = min_rate_categories[region] =
> +            power_categories[region] = i;
> +        expected_number_of_code_bits += expected_bits_table[i];
> +    }

[...]

> +static int siren_decode(AVCodecContext *avctx, void *data,
> +                        int *got_frame, AVPacket *pkt)
> +{
> +    SirenContext *s = avctx->priv_data;
> +    AVFrame *frame = data;
> +    int number_of_valid_coefs = 20 * s->number_of_regions;
> +    int number_of_available_bits =
> +        s->bits_per_frame - s->sample_rate_bits - s->checksum_bits;

s->checksum_bits seems to always be 0, unless I'm missing something.

> +    int envelope_bits, ret;
> +    int frame_error = 0, i, rate_control = 0;
> +    int checksum, calculated_checksum;
> +
> +    if (s->checksum_bits > 0)
> +        memcpy(s->input_frame, pkt->data, FFMIN(pkt->size, 80));

sizeof(s->input_frame) instead of 80?

> +    if ((ret = init_get_bits8(&s->gb, pkt->data, pkt->size)) < 0)
> +        return ret;
> +
> +    envelope_bits =
> +        decode_envelope(s, &s->gb, s->number_of_regions,
> +                        s->decoder_standard_deviation,
> +                        s->absolute_region_power_index, s->esf_adjustment);
> +
> +    number_of_available_bits -= envelope_bits;
> +
> +    for (i = 0; i < s->rate_control_bits; i++) {
> +        rate_control <<= 1;
> +        rate_control |= get_bits1(&s->gb);
> +    }
> +
> +    number_of_available_bits -= s->rate_control_bits;
> +
> +    categorize_regions(s->number_of_regions, number_of_available_bits,
> +                       s->absolute_region_power_index, s->power_categories,
> +                       s->category_balance);
> +
> +    for (i = 0; i < rate_control; i++) {
> +        s->power_categories[s->category_balance[i]]++;
> +    }
> +
> +    number_of_available_bits =
> +        decode_vector(s, s->number_of_regions, number_of_available_bits,
> +                      s->decoder_standard_deviation, s->power_categories,
> +                      s->coefs, s->scale_factor);
> +
> +    if (number_of_available_bits > 0) {
> +        for (i = 0; i < number_of_available_bits; i++) {
> +            if (!get_bits1(&s->gb))
> +                frame_error = 1;
> +        }
> +    } else if (number_of_available_bits < 0
> +               && rate_control + 1 < s->rate_control_possibilities) {
> +        frame_error |= 2;
> +    }
> +
> +    for (i = 0; i < s->number_of_regions; i++) {
> +        if (s->absolute_region_power_index[i] > 33
> +            || s->absolute_region_power_index[i] < -31)
> +            frame_error |= 4;
> +    }
> +
> +    if (s->checksum_bits > 0) {
> +        int idx = 0, sum = 0;
> +
> +        s->bits_per_frame >>= 4;
> +        checksum = s->input_frame[s->bits_per_frame - 1] & ((1 << s->checksum_bits) - 1);
> +        s->input_frame[s->bits_per_frame - 1] &= ~checksum;
> +        do {
> +            sum ^= (s->input_frame[idx] & 0xFFFF) << (idx % 15);
> +        } while (++idx < s->bits_per_frame);
> +
> +        sum = (sum >> 15) ^ (sum & 0x7FFF);
> +        calculated_checksum = 0;
> +        for (i = 0; i < 4; i++) {
> +            int j, temp1 = checksum_table[i] & sum;
> +            for (j = 8; j > 0; j >>= 1) {
> +                int temp2 = temp1 >> j;
> +                temp1 ^= temp2;
> +            }
> +            calculated_checksum <<= 1;
> +            calculated_checksum |= temp1 & 1;
> +        }

AVCRC?

> +
> +        if (checksum != calculated_checksum)
> +            frame_error |= 8;
> +    }
> +
> +    if (frame_error != 0) {
> +        for (i = 0; i < number_of_valid_coefs; i++) {
> +            s->coefs[i] = s->backup_frame[i];
> +            s->backup_frame[i] = 0;
> +        }
> +    } else {
> +        for (i = 0; i < number_of_valid_coefs; i++)
> +            s->backup_frame[i] = s->coefs[i];
> +    }
> +
> +    for (i = number_of_valid_coefs; i < s->number_of_coefs; i++)
> +        s->coefs[i] = 0;
> +
> +    *got_frame = decode_samples(s, s->coefs, s->context, s->number_of_coefs, s->output_frame);
> +    if (*got_frame) {
> +        int16_t *dst;
> +
> +        frame->nb_samples = 320;
> +        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
> +            return ret;
> +        dst = (int16_t *)frame->data[0];
> +
> +        for (i = 0; i < frame->nb_samples; i++) {
> +            dst[i] = av_clip_int16(s->output_frame[i]);

Can't you clip them in decode_samples() instead, so you can replace this
with a memcpy?

> +        }
> +    }
> +
> +    return pkt->size;
> +}
> +
> +static av_cold int siren_close(AVCodecContext *avctx)
> +{
> +    SirenContext *s = avctx->priv_data;
> +
> +    ff_fft_end(&s->fft_ctx);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_siren_decoder = {
> +    .name           = "siren",
> +    .long_name      = NULL_IF_CONFIG_SMALL("Siren"),
> +    .priv_data_size = sizeof(SirenContext),
> +    .type           = AVMEDIA_TYPE_AUDIO,
> +    .id             = AV_CODEC_ID_SIREN,
> +    .init           = siren_init,
> +    .close          = siren_close,
> +    .decode         = siren_decode,
> +    .capabilities   = AV_CODEC_CAP_DR1,
> +};
> 



More information about the ffmpeg-devel mailing list