blob: e17760ec2a94dea97ba472a38f2a90bb95a96f72 [file] [log] [blame]
/***************************************************************************
* This Software has been authored by or modified by PacketVideo Corporation.
* Title and ownership, including all intellectual
* property rights in and to the Software shall remain with PacketVideo
* Corporation. The Software is protected by the patent and copyright laws of
* the United States and by international treaty.
*
* No part of this software may be modified, reproduced or distributed without
* the prior written consent of PacketVideo Corporation.
*
* Copyright (c) 1998, 2007, PacketVideo Corporation. All Rights Reserved.
*
* Release: NJ_SRCHREL_071018
*
***************************************************************************/
#include "oscl_types.h"
#include "sbc.h"
#include "sbc_encoder.h"
#include "sbcenc_allocation.h"
/*$F
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* A2DP specification Adopted version 1.0: Appendix B, Section 12.8, Page 69
* offset4 and offset8 tables for AM_LOUDNESS bit allocation method
*
* Offset table for four subbands
* -----------------------------------------------------------
* offset4 | fs = 16000 | fs = 32000 | fs = 44100 | fs = 48000
* -----------------------------------------------------------
* sb = 0 | -1 | -2 | -2 | -2
* sb = 1 | 0 | 0 | 0 | 0
* sb = 2 | 0 | 0 | 0 | 0
* sb = 3 | 0 | 1 | 1 | 1
* -----------------------------------------------------------
*
* Offset table for eight subbands
* -----------------------------------------------------------
* offset8 | fs = 16000 | fs = 32000 | fs = 44100 | fs = 48000
* -----------------------------------------------------------
* sb = 0 | -2 | -3 | -4 | -4
* sb = 1 | 0 | 0 | 0 | 0
* sb = 2 | 0 | 0 | 0 | 0
* sb = 3 | 0 | 0 | 0 | 0
* sb = 4 | 0 | 0 | 0 | 0
* sb = 5 | 0 | 0 | 0 | 0
* sb = 6 | 0 | 1 | 1 | 1
* sb = 7 | 1 | 2 | 2 | 2
* -----------------------------------------------------------
*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
static const Int sbc_offset4[4][4] =
{
{ -1, 0, 0, 0 },
{ -2, 0, 0, 1 },
{ -2, 0, 0, 1 },
{ -2, 0, 0, 1 }
};
static const Int sbc_offset8[4][8] =
{
{ -2, 0, 0, 0, 0, 0, 0, 1 },
{ -3, 0, 0, 0, 0, 0, 1, 2 },
{ -4, 0, 0, 0, 0, 0, 1, 2 },
{ -4, 0, 0, 0, 0, 0, 1, 2 }
};
void derive_allocation(const sbc_t * sbc, Int bits[2][8])
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
const UInt sf = sbc->sf_index;
Int t_var;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(sbc->channel_mode == CM_MONO || sbc->channel_mode == CM_DUAL_CHANNEL)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
Int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
Int ch, sb, tmp1, tmp2, tmp3, tmp4;
Int *ptr1;
const UWord32 *ptr2;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
for(ch = 0; ch < sbc->channels; ch++)
{
ptr1 = &bitneed[ch][0];
ptr2 = &sbc->scale_factor[ch][0];
if(sbc->allocation_method == AM_SNR)
{
for(sb = sbc->subbands >> 2; sb != 0; sb--)
{
tmp1 = *ptr2++;
tmp2 = *ptr2++;
tmp3 = *ptr2++;
tmp4 = *ptr2++;
*ptr1++ = tmp1;
*ptr1++ = tmp2;
*ptr1++ = tmp3;
*ptr1++ = tmp4;
}
}
else
{
for(sb = 0; sb < sbc->subbands; sb++)
{
if(sbc->scale_factor[ch][sb] == 0)
{
bitneed[ch][sb] = -5;
}
else
{
if(sbc->subbands == 4)
{
loudness = sbc->scale_factor[ch][sb] - sbc_offset4[sf][sb];
}
else
{
loudness = sbc->scale_factor[ch][sb] - sbc_offset8[sf][sb];
}
if(loudness > 0)
{
bitneed[ch][sb] = loudness >> 1;
}
else
{
bitneed[ch][sb] = loudness;
}
}
}
}
max_bitneed = 0;
for(sb = 0; sb < sbc->subbands; sb++)
{
if(bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb];
}
bitcount = 0;
slicecount = 0;
bitslice = max_bitneed + 1;
do
{
bitslice--;
bitcount += slicecount;
slicecount = 0;
for(sb = 0; sb < sbc->subbands; sb++)
{
t_var = bitneed[ch][sb];
if((t_var > bitslice + 1) && (t_var < bitslice + 16))
{
slicecount++;
}
else if(t_var == bitslice + 1)
{
slicecount += 2;
}
}
} while(bitcount + slicecount < sbc->bitpool);
if(bitcount + slicecount == sbc->bitpool)
{
bitcount += slicecount;
bitslice--;
}
for(sb = 0; sb < sbc->subbands; sb++)
{
if(bitneed[ch][sb] < bitslice + 2)
{
bits[ch][sb] = 0;
}
else
{
bits[ch][sb] = bitneed[ch][sb] - bitslice;
if(bits[ch][sb] > 16) bits[ch][sb] = 16;
}
}
sb = 0;
while(bitcount < sbc->bitpool && sb < sbc->subbands)
{
t_var = bits[ch][sb];
if((t_var >= 2) && (t_var < 16))
{
t_var++;
bitcount++;
}
else if((bitneed[ch][sb] == bitslice + 1) && (sbc->bitpool > bitcount + 1))
{
t_var = 2;
bitcount += 2;
}
bits[ch][sb] = t_var;
sb++;
}
sb = 0;
while(bitcount < sbc->bitpool && sb < sbc->subbands)
{
if(bits[ch][sb] < 16)
{
bits[ch][sb]++;
bitcount++;
}
sb++;
}
}
}
else if(sbc->channel_mode == CM_STEREO || sbc->channel_mode == CM_JOINT_STEREO)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
Int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
Int ch, sb, tmp1, tmp2, tmp3, tmp4, tmp;
Int * ptr1, *ptr3, *ptr4, *ptr5;
const UWord32 * ptr2;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
max_bitneed = 0;
if(sbc->allocation_method == AM_SNR)
{
tmp = sbc->subbands >> 2;
ptr1 = &bitneed[0][0];
ptr2 = &sbc->scale_factor[0][0];
for(sb = tmp; sb != 0; sb--)
{
tmp1 = *ptr2++;
tmp2 = *ptr2++;
tmp3 = *ptr2++;
tmp4 = *ptr2++;
*ptr1++ = tmp1;
*ptr1++ = tmp2;
*ptr1++ = tmp3;
*ptr1++ = tmp4;
if(tmp1 > max_bitneed) max_bitneed = tmp1;
if(tmp2 > max_bitneed) max_bitneed = tmp2;
if(tmp3 > max_bitneed) max_bitneed = tmp3;
if(tmp4 > max_bitneed) max_bitneed = tmp4;
}
ptr1 = &bitneed[1][0];
ptr2 = &sbc->scale_factor[1][0];
for(sb = tmp; sb != 0; sb--)
{
tmp1 = *ptr2++;
tmp2 = *ptr2++;
tmp3 = *ptr2++;
tmp4 = *ptr2++;
*ptr1++ = tmp1;
*ptr1++ = tmp2;
*ptr1++ = tmp3;
*ptr1++ = tmp4;
if(tmp1 > max_bitneed) max_bitneed = tmp1;
if(tmp2 > max_bitneed) max_bitneed = tmp2;
if(tmp3 > max_bitneed) max_bitneed = tmp3;
if(tmp4 > max_bitneed) max_bitneed = tmp4;
}
}
else
{
for(ch = 0; ch < 2; ch++)
{
for(sb = 0; sb < sbc->subbands; sb++)
{
if(sbc->scale_factor[ch][sb] == 0)
{
bitneed[ch][sb] = -5;
}
else
{
if(sbc->subbands == 4)
{
loudness = sbc->scale_factor[ch][sb] - sbc_offset4[sf][sb];
}
else
{
loudness = sbc->scale_factor[ch][sb] - sbc_offset8[sf][sb];
}
if(loudness > 0)
{
bitneed[ch][sb] = loudness >> 1;
}
else
{
bitneed[ch][sb] = loudness;
}
}
if(bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb];
}
}
}
bitcount = 0;
slicecount = 0;
bitslice = max_bitneed + 1;
do
{
bitslice--;
bitcount += slicecount;
slicecount = 0;
ptr1 = &bitneed[0][0];
ptr3 = &bitneed[1][0];
for(sb = sbc->subbands; sb != 0; sb--)
{
t_var = *ptr1++;
tmp1 = *ptr3++;
if((t_var > bitslice + 1) && (t_var < bitslice + 16))
slicecount++;
else if(t_var == bitslice + 1)
slicecount += 2;
if((tmp1 > bitslice + 1) && (tmp1 < bitslice + 16))
slicecount++;
else if(tmp1 == bitslice + 1)
slicecount += 2;
}
} while(bitcount + slicecount < sbc->bitpool);
if(bitcount + slicecount == sbc->bitpool)
{
bitcount += slicecount;
bitslice--;
}
ptr1 = &bitneed[0][0];
ptr3 = &bits[0][0];
ptr4 = &bitneed[1][0];
ptr5 = &bits[1][0];
for(sb = sbc->subbands; sb != 0 ; sb--)
{
tmp1 = *ptr1++;
tmp2 = *ptr3;
if(tmp1 < bitslice + 2)
tmp2 = 0;
else
{
tmp2 = tmp1 - bitslice;
if(tmp2 > 16) tmp2 = 16;
}
*ptr3++ = tmp2;
tmp1 = *ptr4++;
tmp2 = *ptr5;
if(tmp1 < bitslice + 2)
tmp2 = 0;
else
{
tmp2 = tmp1 - bitslice;
if(tmp2 > 16) tmp2 = 16;
}
*ptr5++ = tmp2;
}
for(sb = 0; (sb < sbc->subbands) && (bitcount < sbc->bitpool) ; sb++)
{
t_var = bits[0][sb];
if((t_var >= 2) && (t_var < 16))
{
t_var++;
bitcount++;
}
else if((bitneed[0][sb] == bitslice + 1) && (sbc->bitpool > bitcount + 1))
{
t_var = 2;
bitcount += 2;
}
bits[0][sb] = t_var;
if(bitcount < sbc->bitpool)
{
t_var = bits[1][sb];
if((t_var >= 2) && (t_var < 16))
{
t_var++;
bitcount++;
}
else if((bitneed[1][sb] == bitslice + 1) && (sbc->bitpool > bitcount + 1))
{
t_var = 2;
bitcount += 2;
}
bits[1][sb] = t_var;
}
}
for(sb = 0; (sb < sbc->subbands) && (bitcount < sbc->bitpool) ; sb++)
{
for(ch = 0; (ch < 2 && bitcount < sbc->bitpool) ; ch++)
{
if(bits[ch][sb] < 16)
{
bits[ch][sb]++;
bitcount++;
}
}
}
}
}