Older/MediaServer/libflv/source/mpeg4-aac-asc.c

665 lines
19 KiB
C
Raw Normal View History

2024-10-01 00:12:57 +08:00
#include "mpeg4-aac.h"
#include "mpeg4-bits.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
// Table 4.85 - Syntactic elements (p533)
enum {
ID_SCE = 0x0, // single channel element()
ID_CPE = 0x1, // channel_pair_element()
ID_CCE = 0x2, // coupling_channel_element()
ID_LFE = 0x3, // lfe_channel_element()
ID_DSE = 0x4, // data_stream_element()
ID_PCE = 0x5, // program_config_element()
ID_FIL = 0x6, // fill_element()
ID_END = 0x7,
};
// ISO-14496-3 4.4.1.1 Program config element (p488)
// There may be up to 16 such elements per raw data block, each one must have a unique element_instance_tag
// PCEs must come before all other syntactic elements in a raw_data_block().
/*
program_config_element()
{
element_instance_tag; 4 uimsbf
object_type; 2 uimsbf
sampling_frequency_index; 4 uimsbf
num_front_channel_elements; 4 uimsbf
num_side_channel_elements; 4 uimsbf
num_back_channel_elements; 4 uimsbf
num_lfe_channel_elements; 2 uimsbf
num_assoc_data_elements; 3 uimsbf
num_valid_cc_elements; 4 uimsbf
mono_mixdown_present; 1 uimsbf
if (mono_mixdown_present == 1 )
mono_mixdown_element_number; 4 uimsbf
stereo_mixdown_present; 1 uimsbf
if (stereo_mixdown_present == 1 )
stereo_mixdown_element_number; 4 uimsbf
matrix_mixdown_idx_present; 1 uimsbf
if (matrix_mixdown_idx_present == 1 ) {
matrix_mixdown_idx ; 2 uimsbf
pseudo_surround_enable; 1 uimsbf
}
for (i = 0; i < num_front_channel_elements; i++) {
front_element_is_cpe[i]; 1 bslbf
front_element_tag_select[i]; 4 uimsbf
}
for (i = 0; i < num_side_channel_elements; i++) {
side_element_is_cpe[i]; 1 bslbf
side_element_tag_select[i]; 4 uimsbf
}
for (i = 0; i < num_back_channel_elements; i++) {
back_element_is_cpe[i]; 1 bslbf
back_element_tag_select[i]; 4 uimsbf
}
for (i = 0; i < num_lfe_channel_elements; i++)
lfe_element_tag_select[i]; 4 uimsbf
for ( i = 0; i < num_assoc_data_elements; i++)
assoc_data_element_tag_select[i]; 4 uimsbf
for (i = 0; i < num_valid_cc_elements; i++) {
cc_element_is_ind_sw[i]; 1 uimsbf
valid_cc_element_tag_select[i]; 4 uimsbf
}
byte_alignment(); Note 1
comment_field_bytes; 8 uimsbf
for (i = 0; i < comment_field_bytes; i++)
comment_field_data[i]; 8 uimsbf
}
*/
static inline uint64_t mpeg4_bits_copy(struct mpeg4_bits_t* dst, struct mpeg4_bits_t* src, int n)
{
uint64_t v;
v = mpeg4_bits_read_n(src, n);
mpeg4_bits_write_n(dst, v, n);
return v;
}
static int mpeg4_aac_pce_load(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac, struct mpeg4_bits_t* pce)
{
uint64_t i, cpe, tag;
uint64_t element_instance_tag;
uint64_t object_type;
uint64_t sampling_frequency_index;
uint64_t num_front_channel_elements;
uint64_t num_side_channel_elements;
uint64_t num_back_channel_elements;
uint64_t num_lfe_channel_elements;
uint64_t num_assoc_data_elements;
uint64_t num_valid_cc_elements;
uint64_t comment_field_bytes;
aac->channels = 0;
element_instance_tag = mpeg4_bits_copy(pce, bits, 4);
object_type = mpeg4_bits_copy(pce, bits, 2);
sampling_frequency_index = mpeg4_bits_copy(pce, bits, 4);
num_front_channel_elements = mpeg4_bits_copy(pce, bits, 4);
num_side_channel_elements = mpeg4_bits_copy(pce, bits, 4);
num_back_channel_elements = mpeg4_bits_copy(pce, bits, 4);
num_lfe_channel_elements = mpeg4_bits_copy(pce, bits, 2);
num_assoc_data_elements = mpeg4_bits_copy(pce, bits, 3);
num_valid_cc_elements = mpeg4_bits_copy(pce, bits, 4);
if (mpeg4_bits_copy(pce, bits, 1))
mpeg4_bits_copy(pce, bits, 4); // MONO
if (mpeg4_bits_copy(pce, bits, 1))
mpeg4_bits_copy(pce, bits, 4); // STEREO
if (mpeg4_bits_copy(pce, bits, 1))
mpeg4_bits_copy(pce, bits, 3); // Matrix, Pseudo surround
for (i = 0; i < num_front_channel_elements; i++)
{
cpe = mpeg4_bits_copy(pce, bits, 1); // front_element_is_cpe
tag = mpeg4_bits_copy(pce, bits, 4); // front_element_tag_select
aac->channels += (cpe || aac->ps) ? 2 : 1;
}
for (i = 0; i < num_side_channel_elements; i++)
{
cpe = mpeg4_bits_copy(pce, bits, 1); // side_element_is_cpe
tag = mpeg4_bits_copy(pce, bits, 4); // side_element_tag_select
aac->channels += (cpe || aac->ps) ? 2 : 1;
}
for (i = 0; i < num_back_channel_elements; i++)
{
cpe = mpeg4_bits_copy(pce, bits, 1); // back_element_is_cpe
tag = mpeg4_bits_copy(pce, bits, 4); // back_element_tag_select
aac->channels += (cpe || aac->ps) ? 2 : 1;
}
for (i = 0; i < num_lfe_channel_elements; i++)
{
tag = mpeg4_bits_copy(pce, bits, 4); // lfe_element_tag_select
aac->channels += 1;
}
for (i = 0; i < num_assoc_data_elements; i++)
{
tag = mpeg4_bits_copy(pce, bits, 4); // assoc_data_element_tag_select
}
for (i = 0; i < num_valid_cc_elements; i++)
{
cpe = mpeg4_bits_copy(pce, bits, 1); // cc_element_is_ind_sw
tag = mpeg4_bits_copy(pce, bits, 4); // valid_cc_element_tag_select
}
mpeg4_bits_aligment(bits, 8); // byte_alignment();
mpeg4_bits_aligment(pce, 8);
comment_field_bytes = mpeg4_bits_copy(pce, bits, 8);
for (i = 0; i < comment_field_bytes; i++)
mpeg4_bits_copy(pce, bits, 8); // comment_field_data
assert(aac->sampling_frequency_index == sampling_frequency_index);
assert(aac->profile == object_type + 1);
return (int)((pce->bits + 7) / 8);
}
// 4.4.1 Decoder configuration (GASpecificConfig) (p487)
/*
GASpecificConfig (samplingFrequencyIndex, channelConfiguration, audioObjectType)
{
frameLengthFlag; 1 bslbf
dependsOnCoreCoder; 1 bslbf
if (dependsOnCoreCoder) {
coreCoderDelay; 14 uimsbf
}
extensionFlag; 1 bslbf
if (! channelConfiguration) {
program_config_element ();
}
if ((audioObjectType == 6) || (audioObjectType == 20)) {
layerNr; 3 uimsbf
}
if (extensionFlag) {
if (audioObjectType == 22) {
numOfSubFrame; 5 bslbf
layer_length; 11 bslbf
}
if (audioObjectType == 17 || audioObjectType == 19 || audioObjectType == 20 || audioObjectType == 23) {
aacSectionDataResilienceFlag; 1 bslbf
aacScalefactorDataResilienceFlag; 1 bslbf
aacSpectralDataResilienceFlag; 1 bslbf
}
extensionFlag3; 1 bslbf
if (extensionFlag3) {
// tbd in version 3
}
}
}
*/
static int mpeg4_aac_ga_specific_config_load(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac)
{
int extensionFlag;
struct mpeg4_bits_t pce;
mpeg4_bits_read(bits); // frameLengthFlag
if (mpeg4_bits_read(bits)) // dependsOnCoreCoder
mpeg4_bits_read_uint16(bits, 14); // coreCoderDelay
extensionFlag = mpeg4_bits_read(bits); // extensionFlag
if (0 == aac->channel_configuration)
{
mpeg4_bits_init(&pce, aac->pce, sizeof(aac->pce));
aac->npce = mpeg4_aac_pce_load(bits, aac, &pce); // update channel count
}
if (6 == aac->profile || 20 == aac->profile)
mpeg4_bits_read_uint8(bits, 3); // layerNr
if (extensionFlag)
{
if (22 == aac->profile)
{
mpeg4_bits_read_uint8(bits, 5); // numOfSubFrame
mpeg4_bits_read_uint16(bits, 11); // layer_length
}
if (17 == aac->profile || 19 == aac->profile || 20 == aac->profile || 23 == aac->profile)
{
mpeg4_bits_read(bits); // aacSectionDataResilienceFlag
mpeg4_bits_read(bits); // aacScalefactorDataResilienceFlag
mpeg4_bits_read(bits); // aacSpectralDataResilienceFlag
}
if (mpeg4_bits_read(bits)) // extensionFlag3
{
// tbd in version 3
assert(0);
}
}
return mpeg4_bits_error(bits);
}
static int mpeg4_aac_celp_specific_config_load(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac)
{
int ExcitationMode;
if (mpeg4_bits_read(bits)) // isBaseLayer
{
// CelpHeader
ExcitationMode = mpeg4_bits_read(bits);
mpeg4_bits_read(bits); // SampleRateMode
mpeg4_bits_read(bits); // FineRateControl
// Table 3.50 - Description of ExcitationMode
if (ExcitationMode == 1 /*RPE*/)
{
mpeg4_bits_read_n(bits, 3); // RPE_Configuration
}
if (ExcitationMode == 0 /*MPE*/)
{
mpeg4_bits_read_n(bits, 5); // MPE_Configuration
mpeg4_bits_read_n(bits, 2); // NumEnhLayers
mpeg4_bits_read(bits); // BandwidthScalabilityMode
}
}
else
{
if (mpeg4_bits_read(bits)) // isBWSLayer
mpeg4_bits_read_n(bits, 2); // BWS_configuration
else
mpeg4_bits_read_n(bits, 2); // CELP-BRS-id
}
(void)aac;
return mpeg4_bits_error(bits);
}
// ISO/IEC 23003-1 Table 9.1 <20><> Syntax of SpatialSpecificConfig()
/*
SpatialSpecificConfig()
{
bsSamplingFrequencyIndex; 4 uimsbf
if ( bsSamplingFrequencyIndex == 0xf ) {
bsSamplingFrequency; 24 uimsbf
}
bsFrameLength; 7 uimsbf
bsFreqRes; 3 uimsbf
bsTreeConfig; 4 uimsbf
if (bsTreeConfig == <EFBFBD><EFBFBD>0111<EFBFBD><EFBFBD>) {
bsNumInCh; 4 uimsbf
bsNumLFE 2 uimsbf
bsHasSpeakerConfig 1 uimsbf
if ( bsHasSpeakerConfig == 1 ) {
audioChannelLayout = SpeakerConfig3d(); Note 1
}
}
bsQuantMode; 2 uimsbf
bsOneIcc; 1 uimsbf
bsArbitraryDownmix; 1 uimsbf
bsFixedGainSur; 3 uimsbf
bsFixedGainLFE; 3 uimsbf
bsFixedGainDMX; 3 uimsbf
bsMatrixMode; 1 uimsbf
bsTempShapeConfig; 2 uimsbf
bsDecorrConfig; 2 uimsbf
bs3DaudioMode; 1 uimsbf
if ( bsTreeConfig == <EFBFBD><EFBFBD>0111<EFBFBD><EFBFBD> ) {
for (i=0; i< NumInCh - NumLfe; i++) {
defaultCld[i] = 1;
ottModelfe[i] = 0;
}
for (i= NumInCh - NumLfe; i< NumInCh; i++) {
defaultCld[i] = 1;
ottModelfe[i] = 1;
}
}
for (i=0; i<numOttBoxes; i++) { Note 2
OttConfig(i);
}
for (i=0; i<numTttBoxes; i++) { Note 2
TttConfig(i);
}
if (bsTempShapeConfig == 2) {
bsEnvQuantMode 1 uimsbf
}
if (bs3DaudioMode) {
bs3DaudioHRTFset; 2 uimsbf
if (bs3DaudioHRTFset==0) {
ParamHRTFset();
}
}
ByteAlign();
SpatialExtensionConfig();
}
*/
static int SpatialSpecificConfig(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac)
{
return 0;
}
static inline uint8_t mpeg4_aac_get_audio_object_type(struct mpeg4_bits_t* bits)
{
uint8_t audioObjectType;
audioObjectType = mpeg4_bits_read_uint8(bits, 5);
if (31 == audioObjectType)
audioObjectType = 32 + mpeg4_bits_read_uint8(bits, 6);
return audioObjectType;
}
static inline uint8_t mpeg4_aac_get_sampling_frequency(struct mpeg4_bits_t* bits)
{
uint8_t samplingFrequencyIndex;
uint32_t samplingFrequency;
samplingFrequencyIndex = mpeg4_bits_read_uint8(bits, 4);
if (0x0F == samplingFrequencyIndex)
samplingFrequency = mpeg4_bits_read_uint32(bits, 24);
return samplingFrequencyIndex;
}
/// @return asc bits
static size_t mpeg4_aac_audio_specific_config_load3(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac)
{
uint16_t syncExtensionType;
// uint8_t audioObjectType;
// uint8_t samplingFrequencyIndex = 0;
uint8_t extensionSamplingFrequencyIndex = 0;
// uint8_t channelConfiguration = 0;
uint8_t epConfig;
size_t offset;
offset = bits->bits;
aac->profile = mpeg4_aac_get_audio_object_type(bits);
aac->sampling_frequency_index = mpeg4_aac_get_sampling_frequency(bits);
aac->channel_configuration = mpeg4_bits_read_uint8(bits, 4);
aac->channels = mpeg4_aac_channel_count(aac->channel_configuration);
aac->sampling_frequency = mpeg4_aac_audio_frequency_to(aac->sampling_frequency_index);
aac->extension_frequency = aac->sampling_frequency;
aac->extension_channel_configuration = aac->channel_configuration;
if (5 == aac->profile || 29 == aac->profile)
{
aac->extension_audio_object_type = 5;
aac->sbr = 1;
if (29 == aac->profile)
aac->ps = 1;
extensionSamplingFrequencyIndex = mpeg4_aac_get_sampling_frequency(bits);
aac->extension_frequency = mpeg4_aac_audio_frequency_to(extensionSamplingFrequencyIndex);
aac->profile = mpeg4_aac_get_audio_object_type(bits);
if (22 == aac->profile)
aac->extension_channel_configuration = mpeg4_bits_read_uint8(bits, 4);
}
else
{
aac->extension_audio_object_type = 0;
}
switch (aac->profile)
{
case 1: case 2: case 3: case 4: case 6: case 7:
case 17: case 19: case 20: case 21: case 22: case 23:
mpeg4_aac_ga_specific_config_load(bits, aac);
break;
case 8:
mpeg4_aac_celp_specific_config_load(bits, aac);
break;
case 30:
/*sacPayloadEmbedding=*/ mpeg4_bits_read(bits);
break;
default:
assert(0);
return bits->bits - offset;
}
switch (aac->profile)
{
case 17: case 19: case 20: case 21: case 22:
case 23: case 24: case 25: case 26: case 27: case 39:
epConfig = mpeg4_bits_read_uint8(bits, 2);
if (2 == epConfig || 3 == epConfig)
{
// 1.8.2.1 Error protection specific configuration (p96)
// TODO: ErrorProtectionSpecificConfig();
assert(0);
}
if (3 == epConfig)
{
if (mpeg4_bits_read(bits)) // directMapping
{
// tbd
assert(0);
}
}
break;
default:
break; // do nothing;
}
if (5 != aac->extension_audio_object_type && mpeg4_bits_remain(bits) >= 16)
{
syncExtensionType = mpeg4_bits_read_uint16(bits, 11);
if (0x2b7 == syncExtensionType)
{
aac->extension_audio_object_type = mpeg4_aac_get_audio_object_type(bits);
if (5 == aac->extension_audio_object_type)
{
aac->sbr = mpeg4_bits_read(bits);
if (aac->sbr)
{
extensionSamplingFrequencyIndex = mpeg4_aac_get_sampling_frequency(bits);
aac->extension_frequency = mpeg4_aac_audio_frequency_to(extensionSamplingFrequencyIndex);
if (mpeg4_bits_remain(bits) >= 12)
{
syncExtensionType = mpeg4_bits_read_uint16(bits, 11);
if (0x548 == syncExtensionType)
aac->ps = mpeg4_bits_read(bits);
}
}
}
if (22 == aac->extension_audio_object_type)
{
aac->sbr = mpeg4_bits_read(bits);
if (aac->sbr)
{
extensionSamplingFrequencyIndex = mpeg4_aac_get_sampling_frequency(bits);
aac->extension_frequency = mpeg4_aac_audio_frequency_to(extensionSamplingFrequencyIndex);
}
aac->extension_channel_configuration = mpeg4_bits_read_uint8(bits, 4);
}
}
}
return bits->bits - offset;
}
int mpeg4_aac_audio_specific_config_load2(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac)
{
struct mpeg4_bits_t bits;
mpeg4_bits_init(&bits, (void*)data, bytes);
mpeg4_aac_audio_specific_config_load3(&bits, aac);
mpeg4_bits_aligment(&bits, 8);
return mpeg4_bits_error(&bits) ? -1 : (int)(bits.bits / 8);
}
int mpeg4_aac_audio_specific_config_save2(const struct mpeg4_aac_t* aac, uint8_t* data, size_t bytes)
{
if (bytes < 2 + (size_t)aac->npce)
return -1;
memcpy(data + 2, aac->pce, aac->npce);
return 2 + aac->npce;
//data[2 + aac->npce] = 0x56;
//data[2 + aac->npce + 1] = 0xe5;
//data[2 + aac->npce + 2] = 0x00;
//return 2 + aac->npce + 3;
}
int mpeg4_aac_adts_pce_load(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac)
{
int i;
size_t offset = 7;
struct mpeg4_bits_t bits, pce;
if (0 == (data[1] & 0x01)) // protection_absent
{
// number_of_raw_data_blocks_in_frame
for (i = 1; i <= (data[6] & 0x03); i++)
offset += 2; // raw_data_block_position 16-bits
offset += 2; // crc_check 16-bits
}
if (bytes <= offset)
return (int)offset;
mpeg4_bits_init(&bits, (uint8_t*)data + offset, bytes - offset);
if (ID_PCE == mpeg4_bits_read_uint8(&bits, 3))
{
mpeg4_bits_init(&pce, aac->pce, sizeof(aac->pce));
aac->npce = mpeg4_aac_pce_load(&bits, aac, &pce);
return mpeg4_bits_error(&bits) ? -1 : (int)(7 + (pce.bits + 7) / 8);
}
return 7;
}
int mpeg4_aac_adts_pce_save(uint8_t* data, size_t bytes, const struct mpeg4_aac_t* aac)
{
struct mpeg4_aac_t src;
struct mpeg4_bits_t pce, adts;
if ((size_t)aac->npce + 7 > bytes)
return 0;
memcpy(&src, aac, sizeof(src));
// assert(data[1] & 0x01); // disable protection_absent
mpeg4_bits_init(&pce, (uint8_t*)aac->pce, aac->npce);
mpeg4_bits_init(&adts, (uint8_t*)data + 7, bytes - 7);
mpeg4_bits_write_uint8(&adts, ID_PCE, 3);
mpeg4_aac_pce_load(&pce, &src, &adts);
assert(src.channels == aac->channels && (adts.bits + 7) / 8 <= bytes);
return mpeg4_bits_error(&pce) ? 0 : (int)((adts.bits+7) / 8);
}
static size_t mpeg4_aac_stream_mux_config_load3(struct mpeg4_bits_t* bits, struct mpeg4_aac_t* aac)
{
uint8_t audioMuxVersion = 0;
uint8_t numSubFrames;
uint8_t numProgram;
uint8_t numLayer;
uint8_t allStreamsSameTimeFraming;
uint8_t profile = 0;
uint64_t ascLen;
size_t offset;
int streamCnt, prog, lay;
offset = bits->bits;
audioMuxVersion = (uint8_t)mpeg4_bits_read(bits);
if (!audioMuxVersion || 0 == mpeg4_bits_read(bits))
{
if (1 == audioMuxVersion)
/*taraBufferFullness =*/ mpeg4_bits_read_latm(bits);
streamCnt = 0;
allStreamsSameTimeFraming = (uint8_t)mpeg4_bits_read(bits);
numSubFrames = (uint8_t)mpeg4_bits_read_n(bits, 6);
numProgram = (uint8_t)mpeg4_bits_read_n(bits, 4);
for (prog = 0; prog <= numProgram; prog++)
{
numLayer = (uint8_t)mpeg4_bits_read_n(bits, 3);
for (lay = 0; lay <= numLayer; lay++)
{
//progSIndx[streamCnt] = prog;
//laySIndx[streamCnt] = lay;
//streamID[prog][lay] = streamCnt++;
if ( (prog == 0 && lay == 0) || 0 == (uint8_t)mpeg4_bits_read(bits))
{
profile = aac->profile; // previous profile
if (audioMuxVersion == 0) {
mpeg4_aac_audio_specific_config_load3(bits, aac);
} else {
ascLen = mpeg4_bits_read_latm(bits);
ascLen -= mpeg4_aac_audio_specific_config_load3(bits, aac);
mpeg4_bits_skip(bits, (size_t)ascLen);
}
}
//frameLengthType[streamID[prog][lay]] = (uint8_t)mpeg4_bits_read_n(bits, 3);
//switch (frameLengthType[streamID[prog][lay]])
switch (mpeg4_bits_read_n(bits, 3))
{
case 0:
/*latmBufferFullness[streamID[prog][lay]] =*/ (uint8_t)mpeg4_bits_read_n(bits, 8);
if (!allStreamsSameTimeFraming)
{
// fixme
//if ((AudioObjectType[lay] == 6 || AudioObjectType[lay] == 20) &&
// (AudioObjectType[lay - 1] == 8 || AudioObjectType[lay - 1] == 24))
if( (aac->profile == 6 || aac->profile == 20) && (profile == 8 || profile == 24) )
{
/*coreFrameOffset =*/ (uint8_t)mpeg4_bits_read_n(bits, 6);
}
}
break;
case 1:
/*frameLength[streamID[prog][lay]] =*/ (uint16_t)mpeg4_bits_read_n(bits, 9);
break;
case 3:
case 4:
case 5:
/*CELPframeLengthTableIndex[streamID[prog][lay]] =*/ (uint16_t)mpeg4_bits_read_n(bits, 6);
break;
case 6:
case 7:
/*HVXCframeLengthTableIndex[streamID[prog][lay]] =*/ (uint16_t)mpeg4_bits_read_n(bits, 1);
break;
default:
// nothing to do
break;
}
}
}
// otherDataPresent
if (mpeg4_bits_read(bits))
{
if (audioMuxVersion == 1)
{
/*otherDataLenBits =*/ mpeg4_bits_read_latm(bits);
}
else
{
/*otherDataLenBits =*/ mpeg4_bits_read_n(bits, 8); /* helper variable 32bit */
while(mpeg4_bits_read(bits))
{
/*otherDataLenBits <<= 8;
otherDataLenBits +=*/ mpeg4_bits_read_n(bits, 8);
}
}
}
// crcCheckPresent
if (mpeg4_bits_read(bits))
/*crcCheckSum =*/ mpeg4_bits_read_n(bits, 8);
}
else
{
/*tbd*/
}
return bits->bits - offset;
}
int mpeg4_aac_stream_mux_config_load2(const uint8_t* data, size_t bytes, struct mpeg4_aac_t* aac)
{
struct mpeg4_bits_t bits;
mpeg4_bits_init(&bits, (void*)data, bytes);
mpeg4_aac_stream_mux_config_load3(&bits, aac);
mpeg4_bits_aligment(&bits, 8);
return mpeg4_bits_error(&bits) ? -1 : (int)(bits.bits / 8);
}