pipewire/spa/plugins/bluez5/aac-bits.h

191 lines
4.2 KiB
C
Raw Normal View History

/* Spa AAC bits */
/* SPDX-FileCopyrightText: Copyright © 2025 Pauli Virtanen */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_BLUEZ5_AAC_BITS_H
#define SPA_BLUEZ5_AAC_BITS_H
#include <spa/utils/defs.h>
struct bits_out {
uint8_t *buf;
size_t size;
size_t pos;
};
#define BITS_OUT_INIT(buf, size) ((struct bits_out) { (buf), (size), 0 })
static inline void bits_push(struct bits_out *b, uint8_t nbits, uint8_t value)
{
size_t pos = b->pos;
/* Maximally simple, doesn't need to be fast... */
spa_assert(nbits <= 8);
value = ((uint16_t)value) << (8 - nbits);
b->pos += nbits;
while (nbits) {
size_t n = pos / 8;
size_t bit = pos % 8;
if (n >= b->size)
break;
if (bit == 0)
b->buf[n] = 0;
if (value & 0x80)
b->buf[n] |= 1 << (7 - bit);
pos++;
nbits--;
value = ((uint16_t)value) << 1;
}
}
enum aac_aot_type {
AAC_AOT_AAC_LC = 2,
AAC_AOT_ER_AAC_ELD = 39,
};
static inline int aac_frequency_index(int frequency)
{
switch (frequency) {
case 96000: return 0x0;
case 88200: return 0x1;
case 64000: return 0x2;
case 48000: return 0x3;
case 44100: return 0x4;
case 32000: return 0x5;
case 24000: return 0x6;
case 22050: return 0x7;
case 16000: return 0x8;
case 12000: return 0x9;
case 11025: return 0xa;
case 8000: return 0xb;
case 7350: return 0xc;
default:
spa_assert_not_reached();
return -1;
}
}
static inline int aac_channel_index(int channels)
{
switch (channels) {
case 1: return 0x1;
case 2: return 0x2;
default:
spa_assert_not_reached();
return -1;
}
}
/** Write AudioSpecificConfig to given buffer */
static inline int aac_make_asc(void *buf, size_t buf_size, enum aac_aot_type aot,
int frequency, int downscale_frequency, int channels, bool sbr)
{
int freq, down_freq, chan;
struct bits_out b = BITS_OUT_INIT(buf, buf_size);
if ((freq = aac_frequency_index(frequency)) < 0)
return -1;
if ((down_freq = aac_frequency_index(downscale_frequency)) < 0)
return -1;
if ((chan = aac_channel_index(channels)) < 0)
return -1;
switch (aot) {
case AAC_AOT_AAC_LC:
case AAC_AOT_ER_AAC_ELD:
break;
default:
spa_assert_not_reached();
return -EINVAL;
}
if (aot <= 31) {
bits_push(&b, 5, aot);
} else {
bits_push(&b, 5, 31);
bits_push(&b, 6, aot - 32);
}
bits_push(&b, 4, freq); /* frequency index */
bits_push(&b, 4, chan); /* channel configuration */
switch (aot) {
case AAC_AOT_AAC_LC:
/* GASpecificConfig */
bits_push(&b, 1, 0x0); /* frame length flag (1024 length) */
bits_push(&b, 1, 0x0); /* depends on core coder */
bits_push(&b, 1, 0x0); /* extension flag */
break;
case AAC_AOT_ER_AAC_ELD:
/* ELDSpecificConfig */
bits_push(&b, 1, 0x1); /* frame length flag (480 length) */
bits_push(&b, 1, 0x0); /* SectionDataResilience? */
bits_push(&b, 1, 0x0); /* ScalefactorDataResilience? */
bits_push(&b, 1, 0x0); /* SpectralDataResilience? */
bits_push(&b, 1, sbr ? 0x1 : 0x0); /* SBR */
if (sbr) {
bits_push(&b, 1, 0x0); /* ldSbrSamplingRate */
bits_push(&b, 1, 0x0); /* ldSbrCrcFlag */
/* ld_sbr_header */
if (channels != 1 && channels != 2)
return -EINVAL;
/* sbr_header:
* These are just the FDK-AAC default values for 48000/48000...
*/
if (freq != down_freq)
return -EINVAL;
bits_push(&b, 1, 1); /* bs_amp_res */
bits_push(&b, 4, 13); /* bs_start_freq */
bits_push(&b, 4, 7); /* bs_stop_freq */
bits_push(&b, 3, 0); /* bs_xover_band */
bits_push(&b, 2, 0x0); /* bs_reserved */
bits_push(&b, 1, 0x1); /* bs_header_extra_1 */
bits_push(&b, 1, 0x0); /* bs_header_extra_2 */
/* bs_header_extra_1 */
bits_push(&b, 2, 0x1); /* bs_freq_scale */
bits_push(&b, 1, 0x1); /* bs_alter_scale */
bits_push(&b, 2, 0x3); /* bs_noise_bands */
}
if (freq != down_freq) {
bits_push(&b, 4, 0x3); /* ELDEXT_DOWNSCALEINFO */
bits_push(&b, 4, 0x1);
bits_push(&b, 4, down_freq);
bits_push(&b, 4, 0x0);
}
bits_push(&b, 4, 0x0); /* ELDEXT_TERM */
/* epConfig */
bits_push(&b, 2, 0x0);
break;
}
/* byte align */
if (b.pos % 8)
bits_push(&b, 8 - (b.pos % 8), 0x0);
spa_assert(b.pos % 8 == 0);
if (b.pos / 8 >= buf_size) {
spa_assert_not_reached();
return -EINVAL;
}
return b.pos / 8;
}
#endif