694 lines
21 KiB
C
694 lines
21 KiB
C
/*
|
|
** Copyright 2003-2010, VisualOn, Inc.
|
|
**
|
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
** you may not use this file except in compliance with the License.
|
|
** You may obtain a copy of the License at
|
|
**
|
|
** http://www.apache.org/licenses/LICENSE-2.0
|
|
**
|
|
** Unless required by applicable law or agreed to in writing, software
|
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
** See the License for the specific language governing permissions and
|
|
** limitations under the License.
|
|
*/
|
|
/*******************************************************************************
|
|
File: bitenc.c
|
|
|
|
Content: Bitstream encoder functions
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "bitenc.h"
|
|
#include "bit_cnt.h"
|
|
#include "dyn_bits.h"
|
|
#include "qc_data.h"
|
|
#include "interface.h"
|
|
|
|
#define UNUSED(x) (void)(x)
|
|
|
|
static const Word16 globalGainOffset = 100;
|
|
static const Word16 icsReservedBit = 0;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodeSpectralData
|
|
* description: encode spectral data
|
|
* returns: spectral bits used
|
|
*
|
|
*****************************************************************************/
|
|
static Word32 encodeSpectralData(Word16 *sfbOffset,
|
|
SECTION_DATA *sectionData,
|
|
Word16 *quantSpectrum,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
Word16 i,sfb;
|
|
Word16 dbgVal;
|
|
SECTION_INFO* psectioninfo;
|
|
dbgVal = GetBitsAvail(hBitStream);
|
|
|
|
for(i=0; i<sectionData->noOfSections; i++) {
|
|
psectioninfo = &(sectionData->sectionInfo[i]);
|
|
/*
|
|
huffencode spectral data for this section
|
|
*/
|
|
for(sfb=psectioninfo->sfbStart;
|
|
sfb<psectioninfo->sfbStart+psectioninfo->sfbCnt;
|
|
sfb++) {
|
|
codeValues(quantSpectrum+sfbOffset[sfb],
|
|
sfbOffset[sfb+1] - sfbOffset[sfb],
|
|
psectioninfo->codeBook,
|
|
hBitStream);
|
|
}
|
|
}
|
|
|
|
return(GetBitsAvail(hBitStream)-dbgVal);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name:encodeGlobalGain
|
|
* description: encodes Global Gain (common scale factor)
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void encodeGlobalGain(Word16 globalGain,
|
|
Word16 logNorm,
|
|
Word16 scalefac,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
WriteBits(hBitStream, ((globalGain - scalefac) + globalGainOffset-(logNorm << 2)), 8);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name:encodeIcsInfo
|
|
* description: encodes Ics Info
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
|
|
static void encodeIcsInfo(Word16 blockType,
|
|
Word16 windowShape,
|
|
Word16 groupingMask,
|
|
SECTION_DATA *sectionData,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
WriteBits(hBitStream,icsReservedBit,1);
|
|
WriteBits(hBitStream,blockType,2);
|
|
WriteBits(hBitStream,windowShape,1);
|
|
|
|
|
|
switch(blockType){
|
|
case LONG_WINDOW:
|
|
case START_WINDOW:
|
|
case STOP_WINDOW:
|
|
WriteBits(hBitStream,sectionData->maxSfbPerGroup,6);
|
|
|
|
/* No predictor data present */
|
|
WriteBits(hBitStream, 0, 1);
|
|
break;
|
|
|
|
case SHORT_WINDOW:
|
|
WriteBits(hBitStream,sectionData->maxSfbPerGroup,4);
|
|
|
|
/*
|
|
Write grouping bits
|
|
*/
|
|
WriteBits(hBitStream,groupingMask,TRANS_FAC-1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodeSectionData
|
|
* description: encode section data (common Huffman codebooks for adjacent
|
|
* SFB's)
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static Word32 encodeSectionData(SECTION_DATA *sectionData,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
Word16 sectEscapeVal=0,sectLenBits=0;
|
|
Word16 sectLen;
|
|
Word16 i;
|
|
Word16 dbgVal=GetBitsAvail(hBitStream);
|
|
|
|
|
|
|
|
switch(sectionData->blockType)
|
|
{
|
|
case LONG_WINDOW:
|
|
case START_WINDOW:
|
|
case STOP_WINDOW:
|
|
sectEscapeVal = SECT_ESC_VAL_LONG;
|
|
sectLenBits = SECT_BITS_LONG;
|
|
break;
|
|
|
|
case SHORT_WINDOW:
|
|
sectEscapeVal = SECT_ESC_VAL_SHORT;
|
|
sectLenBits = SECT_BITS_SHORT;
|
|
break;
|
|
}
|
|
|
|
for(i=0;i<sectionData->noOfSections;i++) {
|
|
WriteBits(hBitStream,sectionData->sectionInfo[i].codeBook,4);
|
|
sectLen = sectionData->sectionInfo[i].sfbCnt;
|
|
|
|
while(sectLen >= sectEscapeVal) {
|
|
|
|
WriteBits(hBitStream,sectEscapeVal,sectLenBits);
|
|
sectLen = sectLen - sectEscapeVal;
|
|
}
|
|
WriteBits(hBitStream,sectLen,sectLenBits);
|
|
}
|
|
return(GetBitsAvail(hBitStream)-dbgVal);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodeScaleFactorData
|
|
* description: encode DPCM coded scale factors
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static Word32 encodeScaleFactorData(UWord16 *maxValueInSfb,
|
|
SECTION_DATA *sectionData,
|
|
Word16 *scalefac,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
Word16 i,j,lastValScf,deltaScf;
|
|
Word16 dbgVal = GetBitsAvail(hBitStream);
|
|
SECTION_INFO* psectioninfo;
|
|
|
|
lastValScf=scalefac[sectionData->firstScf];
|
|
|
|
for(i=0;i<sectionData->noOfSections;i++){
|
|
psectioninfo = &(sectionData->sectionInfo[i]);
|
|
if (psectioninfo->codeBook != CODE_BOOK_ZERO_NO){
|
|
for (j=psectioninfo->sfbStart;
|
|
j<psectioninfo->sfbStart+psectioninfo->sfbCnt; j++){
|
|
|
|
if(maxValueInSfb[j] == 0) {
|
|
deltaScf = 0;
|
|
}
|
|
else {
|
|
deltaScf = lastValScf - scalefac[j];
|
|
lastValScf = scalefac[j];
|
|
}
|
|
|
|
if(codeScalefactorDelta(deltaScf,hBitStream)){
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return(GetBitsAvail(hBitStream)-dbgVal);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name:encodeMsInfo
|
|
* description: encodes MS-Stereo Info
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void encodeMSInfo(Word16 sfbCnt,
|
|
Word16 grpSfb,
|
|
Word16 maxSfb,
|
|
Word16 msDigest,
|
|
Word16 *jsFlags,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
Word16 sfb, sfbOff;
|
|
|
|
|
|
switch(msDigest)
|
|
{
|
|
case MS_NONE:
|
|
WriteBits(hBitStream,SI_MS_MASK_NONE,2);
|
|
break;
|
|
|
|
case MS_ALL:
|
|
WriteBits(hBitStream,SI_MS_MASK_ALL,2);
|
|
break;
|
|
|
|
case MS_SOME:
|
|
WriteBits(hBitStream,SI_MS_MASK_SOME,2);
|
|
for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) {
|
|
for(sfb=0; sfb<maxSfb; sfb++) {
|
|
|
|
if(jsFlags[sfbOff+sfb] & MS_ON) {
|
|
WriteBits(hBitStream,1,1);
|
|
}
|
|
else{
|
|
WriteBits(hBitStream,0,1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodeTnsData
|
|
* description: encode TNS data (filter order, coeffs, ..)
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void encodeTnsData(TNS_INFO tnsInfo,
|
|
Word16 blockType,
|
|
HANDLE_BIT_BUF hBitStream) {
|
|
Word16 i,k;
|
|
Flag tnsPresent;
|
|
Word16 numOfWindows;
|
|
Word16 coefBits;
|
|
Flag isShort;
|
|
|
|
|
|
if (blockType==2) {
|
|
isShort = 1;
|
|
numOfWindows = TRANS_FAC;
|
|
}
|
|
else {
|
|
isShort = 0;
|
|
numOfWindows = 1;
|
|
}
|
|
|
|
tnsPresent=0;
|
|
for (i=0; i<numOfWindows; i++) {
|
|
|
|
if (tnsInfo.tnsActive[i]) {
|
|
tnsPresent=1;
|
|
}
|
|
}
|
|
|
|
if (tnsPresent==0) {
|
|
WriteBits(hBitStream,0,1);
|
|
}
|
|
else{ /* there is data to be written*/
|
|
WriteBits(hBitStream,1,1); /*data_present */
|
|
for (i=0; i<numOfWindows; i++) {
|
|
|
|
WriteBits(hBitStream,tnsInfo.tnsActive[i],(isShort?1:2));
|
|
|
|
if (tnsInfo.tnsActive[i]) {
|
|
|
|
WriteBits(hBitStream,((tnsInfo.coefRes[i] - 4)==0?1:0),1);
|
|
|
|
WriteBits(hBitStream,tnsInfo.length[i],(isShort?4:6));
|
|
|
|
WriteBits(hBitStream,tnsInfo.order[i],(isShort?3:5));
|
|
|
|
if (tnsInfo.order[i]){
|
|
WriteBits(hBitStream, FILTER_DIRECTION, 1);
|
|
|
|
if(tnsInfo.coefRes[i] == 4) {
|
|
coefBits = 3;
|
|
for(k=0; k<tnsInfo.order[i]; k++) {
|
|
|
|
if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] > 3 ||
|
|
tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -4) {
|
|
coefBits = 4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
coefBits = 2;
|
|
for(k=0; k<tnsInfo.order[i]; k++) {
|
|
|
|
if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] > 1 ||
|
|
tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -2) {
|
|
coefBits = 3;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
WriteBits(hBitStream, tnsInfo.coefRes[i] - coefBits, 1); /*coef_compres*/
|
|
for (k=0; k<tnsInfo.order[i]; k++ ) {
|
|
static const Word16 rmask[] = {0,1,3,7,15};
|
|
|
|
WriteBits(hBitStream,tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] & rmask[coefBits],coefBits);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodeGainControlData
|
|
* description: unsupported
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void encodeGainControlData(HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
WriteBits(hBitStream,0,1);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: encodePulseData
|
|
* description: not supported yet (dummy)
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void encodePulseData(HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
WriteBits(hBitStream,0,1);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: WriteIndividualChannelStream
|
|
* description: management of write process of individual channel stream
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void
|
|
writeIndividualChannelStream(Flag commonWindow,
|
|
Word16 mdctScale,
|
|
Word16 windowShape,
|
|
Word16 groupingMask,
|
|
Word16 *sfbOffset,
|
|
Word16 scf[],
|
|
UWord16 *maxValueInSfb,
|
|
Word16 globalGain,
|
|
Word16 quantSpec[],
|
|
SECTION_DATA *sectionData,
|
|
HANDLE_BIT_BUF hBitStream,
|
|
TNS_INFO tnsInfo)
|
|
{
|
|
Word16 logNorm;
|
|
|
|
logNorm = LOG_NORM_PCM - (mdctScale + 1);
|
|
|
|
encodeGlobalGain(globalGain, logNorm,scf[sectionData->firstScf], hBitStream);
|
|
|
|
|
|
if(!commonWindow) {
|
|
encodeIcsInfo(sectionData->blockType, windowShape, groupingMask, sectionData, hBitStream);
|
|
}
|
|
|
|
encodeSectionData(sectionData, hBitStream);
|
|
|
|
encodeScaleFactorData(maxValueInSfb,
|
|
sectionData,
|
|
scf,
|
|
hBitStream);
|
|
|
|
encodePulseData(hBitStream);
|
|
|
|
encodeTnsData(tnsInfo, sectionData->blockType, hBitStream);
|
|
|
|
encodeGainControlData(hBitStream);
|
|
|
|
encodeSpectralData(sfbOffset,
|
|
sectionData,
|
|
quantSpec,
|
|
hBitStream);
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: writeSingleChannelElement
|
|
* description: write single channel element to bitstream
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static Word16 writeSingleChannelElement(Word16 instanceTag,
|
|
Word16 *sfbOffset,
|
|
QC_OUT_CHANNEL* qcOutChannel,
|
|
HANDLE_BIT_BUF hBitStream,
|
|
TNS_INFO tnsInfo)
|
|
{
|
|
WriteBits(hBitStream,ID_SCE,3);
|
|
WriteBits(hBitStream,instanceTag,4);
|
|
writeIndividualChannelStream(0,
|
|
qcOutChannel->mdctScale,
|
|
qcOutChannel->windowShape,
|
|
qcOutChannel->groupingMask,
|
|
sfbOffset,
|
|
qcOutChannel->scf,
|
|
qcOutChannel->maxValueInSfb,
|
|
qcOutChannel->globalGain,
|
|
qcOutChannel->quantSpec,
|
|
&(qcOutChannel->sectionData),
|
|
hBitStream,
|
|
tnsInfo
|
|
);
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: writeChannelPairElement
|
|
* description:
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static Word16 writeChannelPairElement(Word16 instanceTag,
|
|
Word16 msDigest,
|
|
Word16 msFlags[MAX_GROUPED_SFB],
|
|
Word16 *sfbOffset[2],
|
|
QC_OUT_CHANNEL qcOutChannel[2],
|
|
HANDLE_BIT_BUF hBitStream,
|
|
TNS_INFO tnsInfo[2])
|
|
{
|
|
WriteBits(hBitStream,ID_CPE,3);
|
|
WriteBits(hBitStream,instanceTag,4);
|
|
WriteBits(hBitStream,1,1); /* common window */
|
|
|
|
encodeIcsInfo(qcOutChannel[0].sectionData.blockType,
|
|
qcOutChannel[0].windowShape,
|
|
qcOutChannel[0].groupingMask,
|
|
&(qcOutChannel[0].sectionData),
|
|
hBitStream);
|
|
|
|
encodeMSInfo(qcOutChannel[0].sectionData.sfbCnt,
|
|
qcOutChannel[0].sectionData.sfbPerGroup,
|
|
qcOutChannel[0].sectionData.maxSfbPerGroup,
|
|
msDigest,
|
|
msFlags,
|
|
hBitStream);
|
|
|
|
writeIndividualChannelStream(1,
|
|
qcOutChannel[0].mdctScale,
|
|
qcOutChannel[0].windowShape,
|
|
qcOutChannel[0].groupingMask,
|
|
sfbOffset[0],
|
|
qcOutChannel[0].scf,
|
|
qcOutChannel[0].maxValueInSfb,
|
|
qcOutChannel[0].globalGain,
|
|
qcOutChannel[0].quantSpec,
|
|
&(qcOutChannel[0].sectionData),
|
|
hBitStream,
|
|
tnsInfo[0]);
|
|
|
|
writeIndividualChannelStream(1,
|
|
qcOutChannel[1].mdctScale,
|
|
qcOutChannel[1].windowShape,
|
|
qcOutChannel[1].groupingMask,
|
|
sfbOffset[1],
|
|
qcOutChannel[1].scf,
|
|
qcOutChannel[1].maxValueInSfb,
|
|
qcOutChannel[1].globalGain,
|
|
qcOutChannel[1].quantSpec,
|
|
&(qcOutChannel[1].sectionData),
|
|
hBitStream,
|
|
tnsInfo[1]);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: writeFillElement
|
|
* description: write fill elements to bitstream
|
|
* returns: none
|
|
*
|
|
*****************************************************************************/
|
|
static void writeFillElement( const UWord8 *ancBytes,
|
|
Word16 totFillBits,
|
|
HANDLE_BIT_BUF hBitStream)
|
|
{
|
|
Word16 i;
|
|
Word16 cnt,esc_count;
|
|
|
|
/*
|
|
Write fill Element(s):
|
|
amount of a fill element can be 7+X*8 Bits, X element of [0..270]
|
|
*/
|
|
|
|
while(totFillBits >= (3+4)) {
|
|
cnt = min(((totFillBits - (3+4)) >> 3), ((1<<4)-1));
|
|
|
|
WriteBits(hBitStream,ID_FIL,3);
|
|
WriteBits(hBitStream,cnt,4);
|
|
|
|
totFillBits = totFillBits - (3+4);
|
|
|
|
|
|
if (cnt == (1<<4)-1) {
|
|
|
|
esc_count = min( ((totFillBits >> 3) - ((1<<4)-1)), (1<<8)-1);
|
|
WriteBits(hBitStream,esc_count,8);
|
|
totFillBits = (totFillBits - 8);
|
|
cnt = cnt + (esc_count - 1);
|
|
}
|
|
|
|
for(i=0;i<cnt;i++) {
|
|
|
|
if(ancBytes)
|
|
WriteBits(hBitStream, *ancBytes++,8);
|
|
else
|
|
WriteBits(hBitStream,0,8);
|
|
totFillBits = totFillBits - 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* function name: WriteBitStream
|
|
* description: main function of write bitsteam process
|
|
* returns: 0 if success
|
|
*
|
|
*****************************************************************************/
|
|
Word16 WriteBitstream (HANDLE_BIT_BUF hBitStream,
|
|
ELEMENT_INFO elInfo,
|
|
QC_OUT *qcOut,
|
|
PSY_OUT *psyOut,
|
|
Word16 *globUsedBits,
|
|
const UWord8 *ancBytes,
|
|
Word16 sampindex
|
|
) /* returns error code */
|
|
{
|
|
Word16 bitMarkUp;
|
|
Word16 elementUsedBits;
|
|
Word16 frameBits=0;
|
|
|
|
UNUSED(ancBytes);
|
|
|
|
/* struct bitbuffer bsWriteCopy; */
|
|
bitMarkUp = GetBitsAvail(hBitStream);
|
|
if(qcOut->qcElement.adtsUsed) /* write adts header*/
|
|
{
|
|
WriteBits(hBitStream, 0xFFF, 12); /* 12 bit Syncword */
|
|
WriteBits(hBitStream, 1, 1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */
|
|
WriteBits(hBitStream, 0, 2); /* layer == 0 */
|
|
WriteBits(hBitStream, 1, 1); /* protection absent */
|
|
WriteBits(hBitStream, 1, 2); /* profile */
|
|
WriteBits(hBitStream, sampindex, 4); /* sampling rate */
|
|
WriteBits(hBitStream, 0, 1); /* private bit */
|
|
WriteBits(hBitStream, elInfo.nChannelsInEl, 3); /* ch. config (must be > 0) */
|
|
/* simply using numChannels only works for
|
|
6 channels or less, else a channel
|
|
configuration should be written */
|
|
WriteBits(hBitStream, 0, 1); /* original/copy */
|
|
WriteBits(hBitStream, 0, 1); /* home */
|
|
|
|
/* Variable ADTS header */
|
|
WriteBits(hBitStream, 0, 1); /* copyr. id. bit */
|
|
WriteBits(hBitStream, 0, 1); /* copyr. id. start */
|
|
WriteBits(hBitStream, *globUsedBits >> 3, 13);
|
|
WriteBits(hBitStream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */
|
|
WriteBits(hBitStream, 0, 2); /* raw data blocks (0+1=1) */
|
|
}
|
|
|
|
*globUsedBits=0;
|
|
|
|
{
|
|
|
|
Word16 *sfbOffset[2];
|
|
TNS_INFO tnsInfo[2];
|
|
elementUsedBits = 0;
|
|
|
|
switch (elInfo.elType) {
|
|
|
|
case ID_SCE: /* single channel */
|
|
sfbOffset[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets;
|
|
tnsInfo[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo;
|
|
|
|
writeSingleChannelElement(elInfo.instanceTag,
|
|
sfbOffset[0],
|
|
&qcOut->qcChannel[elInfo.ChannelIndex[0]],
|
|
hBitStream,
|
|
tnsInfo[0]);
|
|
break;
|
|
|
|
case ID_CPE: /* channel pair */
|
|
{
|
|
Word16 msDigest;
|
|
Word16 *msFlags = psyOut->psyOutElement.toolsInfo.msMask;
|
|
msDigest = psyOut->psyOutElement.toolsInfo.msDigest;
|
|
sfbOffset[0] =
|
|
psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets;
|
|
sfbOffset[1] =
|
|
psyOut->psyOutChannel[elInfo.ChannelIndex[1]].sfbOffsets;
|
|
|
|
tnsInfo[0]=
|
|
psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo;
|
|
tnsInfo[1]=
|
|
psyOut->psyOutChannel[elInfo.ChannelIndex[1]].tnsInfo;
|
|
writeChannelPairElement(elInfo.instanceTag,
|
|
msDigest,
|
|
msFlags,
|
|
sfbOffset,
|
|
&qcOut->qcChannel[elInfo.ChannelIndex[0]],
|
|
hBitStream,
|
|
tnsInfo);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(1);
|
|
|
|
} /* switch */
|
|
|
|
elementUsedBits = elementUsedBits - bitMarkUp;
|
|
bitMarkUp = GetBitsAvail(hBitStream);
|
|
frameBits = frameBits + elementUsedBits + bitMarkUp;
|
|
|
|
}
|
|
|
|
writeFillElement(NULL,
|
|
qcOut->totFillBits,
|
|
hBitStream);
|
|
|
|
WriteBits(hBitStream,ID_END,3);
|
|
|
|
/* byte alignement */
|
|
WriteBits(hBitStream,0, (8 - (hBitStream->cntBits & 7)) & 7);
|
|
|
|
*globUsedBits = *globUsedBits- bitMarkUp;
|
|
bitMarkUp = GetBitsAvail(hBitStream);
|
|
*globUsedBits = *globUsedBits + bitMarkUp;
|
|
frameBits = frameBits + *globUsedBits;
|
|
|
|
|
|
if (frameBits != (qcOut->totStaticBitsUsed+qcOut->totDynBitsUsed + qcOut->totAncBitsUsed +
|
|
qcOut->totFillBits + qcOut->alignBits)) {
|
|
return(-1);
|
|
}
|
|
return(0);
|
|
}
|