• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2003-2010, VisualOn, Inc.
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 /*******************************************************************************
17 	File:		bitenc.c
18 
19 	Content:	Bitstream encoder functions
20 
21 *******************************************************************************/
22 
23 #include "bitenc.h"
24 #include "bit_cnt.h"
25 #include "dyn_bits.h"
26 #include "qc_data.h"
27 #include "interface.h"
28 
29 #define UNUSED(x) (void)(x)
30 
31 static const  Word16 globalGainOffset = 100;
32 static const  Word16 icsReservedBit   = 0;
33 
34 
35 /*****************************************************************************
36 *
37 * function name: encodeSpectralData
38 * description:  encode spectral data
39 * returns:      spectral bits used
40 *
41 *****************************************************************************/
encodeSpectralData(Word16 * sfbOffset,SECTION_DATA * sectionData,Word16 * quantSpectrum,HANDLE_BIT_BUF hBitStream)42 static Word32 encodeSpectralData(Word16             *sfbOffset,
43                                  SECTION_DATA       *sectionData,
44                                  Word16             *quantSpectrum,
45                                  HANDLE_BIT_BUF      hBitStream)
46 {
47   Word16 i,sfb;
48   Word16 dbgVal;
49   SECTION_INFO* psectioninfo;
50   dbgVal = GetBitsAvail(hBitStream);
51 
52   for(i=0; i<sectionData->noOfSections; i++) {
53     psectioninfo = &(sectionData->sectionInfo[i]);
54 	/*
55        huffencode spectral data for this section
56     */
57     for(sfb=psectioninfo->sfbStart;
58         sfb<psectioninfo->sfbStart+psectioninfo->sfbCnt;
59         sfb++) {
60       codeValues(quantSpectrum+sfbOffset[sfb],
61                  sfbOffset[sfb+1] - sfbOffset[sfb],
62                  psectioninfo->codeBook,
63                  hBitStream);
64     }
65   }
66 
67   return(GetBitsAvail(hBitStream)-dbgVal);
68 }
69 
70 /*****************************************************************************
71 *
72 * function name:encodeGlobalGain
73 * description: encodes Global Gain (common scale factor)
74 * returns:     none
75 *
76 *****************************************************************************/
encodeGlobalGain(Word16 globalGain,Word16 logNorm,Word16 scalefac,HANDLE_BIT_BUF hBitStream)77 static void encodeGlobalGain(Word16 globalGain,
78                              Word16 logNorm,
79                              Word16 scalefac,
80                              HANDLE_BIT_BUF hBitStream)
81 {
82   WriteBits(hBitStream, ((globalGain - scalefac) + globalGainOffset-(logNorm << 2)), 8);
83 }
84 
85 
86 /*****************************************************************************
87 *
88 * function name:encodeIcsInfo
89 * description: encodes Ics Info
90 * returns:     none
91 *
92 *****************************************************************************/
93 
encodeIcsInfo(Word16 blockType,Word16 windowShape,Word16 groupingMask,SECTION_DATA * sectionData,HANDLE_BIT_BUF hBitStream)94 static void encodeIcsInfo(Word16 blockType,
95                           Word16 windowShape,
96                           Word16 groupingMask,
97                           SECTION_DATA *sectionData,
98                           HANDLE_BIT_BUF  hBitStream)
99 {
100   WriteBits(hBitStream,icsReservedBit,1);
101   WriteBits(hBitStream,blockType,2);
102   WriteBits(hBitStream,windowShape,1);
103 
104 
105   switch(blockType){
106     case LONG_WINDOW:
107     case START_WINDOW:
108     case STOP_WINDOW:
109       WriteBits(hBitStream,sectionData->maxSfbPerGroup,6);
110 
111       /* No predictor data present */
112       WriteBits(hBitStream, 0, 1);
113       break;
114 
115     case SHORT_WINDOW:
116       WriteBits(hBitStream,sectionData->maxSfbPerGroup,4);
117 
118       /*
119       Write grouping bits
120       */
121       WriteBits(hBitStream,groupingMask,TRANS_FAC-1);
122       break;
123   }
124 }
125 
126 /*****************************************************************************
127 *
128 * function name: encodeSectionData
129 * description:  encode section data (common Huffman codebooks for adjacent
130 *               SFB's)
131 * returns:      none
132 *
133 *****************************************************************************/
encodeSectionData(SECTION_DATA * sectionData,HANDLE_BIT_BUF hBitStream)134 static Word32 encodeSectionData(SECTION_DATA *sectionData,
135                                 HANDLE_BIT_BUF hBitStream)
136 {
137   Word16 sectEscapeVal=0,sectLenBits=0;
138   Word16 sectLen;
139   Word16 i;
140   Word16 dbgVal=GetBitsAvail(hBitStream);
141 
142 
143 
144   switch(sectionData->blockType)
145   {
146     case LONG_WINDOW:
147     case START_WINDOW:
148     case STOP_WINDOW:
149       sectEscapeVal = SECT_ESC_VAL_LONG;
150       sectLenBits   = SECT_BITS_LONG;
151       break;
152 
153     case SHORT_WINDOW:
154       sectEscapeVal = SECT_ESC_VAL_SHORT;
155       sectLenBits   = SECT_BITS_SHORT;
156       break;
157   }
158 
159   for(i=0;i<sectionData->noOfSections;i++) {
160     WriteBits(hBitStream,sectionData->sectionInfo[i].codeBook,4);
161     sectLen = sectionData->sectionInfo[i].sfbCnt;
162 
163     while(sectLen >= sectEscapeVal) {
164 
165       WriteBits(hBitStream,sectEscapeVal,sectLenBits);
166       sectLen = sectLen - sectEscapeVal;
167     }
168     WriteBits(hBitStream,sectLen,sectLenBits);
169   }
170   return(GetBitsAvail(hBitStream)-dbgVal);
171 }
172 
173 /*****************************************************************************
174 *
175 * function name: encodeScaleFactorData
176 * description:  encode DPCM coded scale factors
177 * returns:      none
178 *
179 *****************************************************************************/
encodeScaleFactorData(UWord16 * maxValueInSfb,SECTION_DATA * sectionData,Word16 * scalefac,HANDLE_BIT_BUF hBitStream)180 static Word32 encodeScaleFactorData(UWord16        *maxValueInSfb,
181                                     SECTION_DATA   *sectionData,
182                                     Word16         *scalefac,
183                                     HANDLE_BIT_BUF  hBitStream)
184 {
185   Word16 i,j,lastValScf,deltaScf;
186   Word16 dbgVal = GetBitsAvail(hBitStream);
187   SECTION_INFO* psectioninfo;
188 
189   lastValScf=scalefac[sectionData->firstScf];
190 
191   for(i=0;i<sectionData->noOfSections;i++){
192     psectioninfo = &(sectionData->sectionInfo[i]);
193     if (psectioninfo->codeBook != CODE_BOOK_ZERO_NO){
194       for (j=psectioninfo->sfbStart;
195            j<psectioninfo->sfbStart+psectioninfo->sfbCnt; j++){
196 
197         if(maxValueInSfb[j] == 0) {
198           deltaScf = 0;
199         }
200         else {
201           deltaScf = lastValScf - scalefac[j];
202           lastValScf = scalefac[j];
203         }
204 
205         if(codeScalefactorDelta(deltaScf,hBitStream)){
206           return(1);
207         }
208       }
209     }
210 
211   }
212   return(GetBitsAvail(hBitStream)-dbgVal);
213 }
214 
215 /*****************************************************************************
216 *
217 * function name:encodeMsInfo
218 * description: encodes MS-Stereo Info
219 * returns:     none
220 *
221 *****************************************************************************/
encodeMSInfo(Word16 sfbCnt,Word16 grpSfb,Word16 maxSfb,Word16 msDigest,Word16 * jsFlags,HANDLE_BIT_BUF hBitStream)222 static void encodeMSInfo(Word16          sfbCnt,
223                          Word16          grpSfb,
224                          Word16          maxSfb,
225                          Word16          msDigest,
226                          Word16         *jsFlags,
227                          HANDLE_BIT_BUF  hBitStream)
228 {
229   Word16 sfb, sfbOff;
230 
231 
232   switch(msDigest)
233   {
234     case MS_NONE:
235       WriteBits(hBitStream,SI_MS_MASK_NONE,2);
236       break;
237 
238     case MS_ALL:
239       WriteBits(hBitStream,SI_MS_MASK_ALL,2);
240       break;
241 
242     case MS_SOME:
243       WriteBits(hBitStream,SI_MS_MASK_SOME,2);
244       for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) {
245         for(sfb=0; sfb<maxSfb; sfb++) {
246 
247           if(jsFlags[sfbOff+sfb] & MS_ON) {
248             WriteBits(hBitStream,1,1);
249           }
250           else{
251             WriteBits(hBitStream,0,1);
252           }
253         }
254       }
255       break;
256   }
257 
258 }
259 
260 /*****************************************************************************
261 *
262 * function name: encodeTnsData
263 * description:  encode TNS data (filter order, coeffs, ..)
264 * returns:      none
265 *
266 *****************************************************************************/
encodeTnsData(TNS_INFO tnsInfo,Word16 blockType,HANDLE_BIT_BUF hBitStream)267 static void encodeTnsData(TNS_INFO tnsInfo,
268                           Word16 blockType,
269                           HANDLE_BIT_BUF hBitStream) {
270   Word16 i,k;
271   Flag tnsPresent;
272   Word16 numOfWindows;
273   Word16 coefBits;
274   Flag isShort;
275 
276 
277   if (blockType==2) {
278     isShort = 1;
279     numOfWindows = TRANS_FAC;
280   }
281   else {
282     isShort = 0;
283     numOfWindows = 1;
284   }
285 
286   tnsPresent=0;
287   for (i=0; i<numOfWindows; i++) {
288 
289     if (tnsInfo.tnsActive[i]) {
290       tnsPresent=1;
291     }
292   }
293 
294   if (tnsPresent==0) {
295     WriteBits(hBitStream,0,1);
296   }
297   else{ /* there is data to be written*/
298     WriteBits(hBitStream,1,1); /*data_present */
299     for (i=0; i<numOfWindows; i++) {
300 
301       WriteBits(hBitStream,tnsInfo.tnsActive[i],(isShort?1:2));
302 
303       if (tnsInfo.tnsActive[i]) {
304 
305         WriteBits(hBitStream,((tnsInfo.coefRes[i] - 4)==0?1:0),1);
306 
307         WriteBits(hBitStream,tnsInfo.length[i],(isShort?4:6));
308 
309         WriteBits(hBitStream,tnsInfo.order[i],(isShort?3:5));
310 
311         if (tnsInfo.order[i]){
312           WriteBits(hBitStream, FILTER_DIRECTION, 1);
313 
314           if(tnsInfo.coefRes[i] == 4) {
315             coefBits = 3;
316             for(k=0; k<tnsInfo.order[i]; k++) {
317 
318               if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] > 3 ||
319                   tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -4) {
320                 coefBits = 4;
321                 break;
322               }
323             }
324           }
325           else {
326             coefBits = 2;
327             for(k=0; k<tnsInfo.order[i]; k++) {
328 
329               if (tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] > 1 ||
330                   tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] < -2) {
331                 coefBits = 3;
332                 break;
333               }
334             }
335           }
336           WriteBits(hBitStream, tnsInfo.coefRes[i] - coefBits, 1); /*coef_compres*/
337           for (k=0; k<tnsInfo.order[i]; k++ ) {
338             static const Word16 rmask[] = {0,1,3,7,15};
339 
340             WriteBits(hBitStream,tnsInfo.coef[i*TNS_MAX_ORDER_SHORT+k] & rmask[coefBits],coefBits);
341           }
342         }
343       }
344     }
345   }
346 
347 }
348 
349 /*****************************************************************************
350 *
351 * function name: encodeGainControlData
352 * description:  unsupported
353 * returns:      none
354 *
355 *****************************************************************************/
encodeGainControlData(HANDLE_BIT_BUF hBitStream)356 static void encodeGainControlData(HANDLE_BIT_BUF hBitStream)
357 {
358   WriteBits(hBitStream,0,1);
359 }
360 
361 /*****************************************************************************
362 *
363 * function name: encodePulseData
364 * description:  not supported yet (dummy)
365 * returns:      none
366 *
367 *****************************************************************************/
encodePulseData(HANDLE_BIT_BUF hBitStream)368 static void encodePulseData(HANDLE_BIT_BUF hBitStream)
369 {
370   WriteBits(hBitStream,0,1);
371 }
372 
373 
374 /*****************************************************************************
375 *
376 * function name: WriteIndividualChannelStream
377 * description:  management of write process of individual channel stream
378 * returns:      none
379 *
380 *****************************************************************************/
381 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)382 writeIndividualChannelStream(Flag   commonWindow,
383                              Word16 mdctScale,
384                              Word16 windowShape,
385                              Word16 groupingMask,
386                              Word16 *sfbOffset,
387                              Word16 scf[],
388                              UWord16 *maxValueInSfb,
389                              Word16 globalGain,
390                              Word16 quantSpec[],
391                              SECTION_DATA *sectionData,
392                              HANDLE_BIT_BUF hBitStream,
393                              TNS_INFO tnsInfo)
394 {
395   Word16 logNorm;
396 
397   logNorm = LOG_NORM_PCM - (mdctScale + 1);
398 
399   encodeGlobalGain(globalGain, logNorm,scf[sectionData->firstScf], hBitStream);
400 
401 
402   if(!commonWindow) {
403     encodeIcsInfo(sectionData->blockType, windowShape, groupingMask, sectionData, hBitStream);
404   }
405 
406   encodeSectionData(sectionData, hBitStream);
407 
408   encodeScaleFactorData(maxValueInSfb,
409                         sectionData,
410                         scf,
411                         hBitStream);
412 
413   encodePulseData(hBitStream);
414 
415   encodeTnsData(tnsInfo, sectionData->blockType, hBitStream);
416 
417   encodeGainControlData(hBitStream);
418 
419   encodeSpectralData(sfbOffset,
420                      sectionData,
421                      quantSpec,
422                      hBitStream);
423 
424 }
425 
426 /*****************************************************************************
427 *
428 * function name: writeSingleChannelElement
429 * description:  write single channel element to bitstream
430 * returns:      none
431 *
432 *****************************************************************************/
writeSingleChannelElement(Word16 instanceTag,Word16 * sfbOffset,QC_OUT_CHANNEL * qcOutChannel,HANDLE_BIT_BUF hBitStream,TNS_INFO tnsInfo)433 static Word16 writeSingleChannelElement(Word16 instanceTag,
434                                         Word16 *sfbOffset,
435                                         QC_OUT_CHANNEL* qcOutChannel,
436                                         HANDLE_BIT_BUF hBitStream,
437                                         TNS_INFO tnsInfo)
438 {
439   WriteBits(hBitStream,ID_SCE,3);
440   WriteBits(hBitStream,instanceTag,4);
441   writeIndividualChannelStream(0,
442                                qcOutChannel->mdctScale,
443                                qcOutChannel->windowShape,
444                                qcOutChannel->groupingMask,
445                                sfbOffset,
446                                qcOutChannel->scf,
447                                qcOutChannel->maxValueInSfb,
448                                qcOutChannel->globalGain,
449                                qcOutChannel->quantSpec,
450                                &(qcOutChannel->sectionData),
451                                hBitStream,
452                                tnsInfo
453                                );
454   return(0);
455 }
456 
457 
458 
459 /*****************************************************************************
460 *
461 * function name: writeChannelPairElement
462 * description:
463 * returns:      none
464 *
465 *****************************************************************************/
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])466 static Word16 writeChannelPairElement(Word16 instanceTag,
467                                       Word16 msDigest,
468                                       Word16 msFlags[MAX_GROUPED_SFB],
469                                       Word16 *sfbOffset[2],
470                                       QC_OUT_CHANNEL qcOutChannel[2],
471                                       HANDLE_BIT_BUF hBitStream,
472                                       TNS_INFO tnsInfo[2])
473 {
474   WriteBits(hBitStream,ID_CPE,3);
475   WriteBits(hBitStream,instanceTag,4);
476   WriteBits(hBitStream,1,1); /* common window */
477 
478   encodeIcsInfo(qcOutChannel[0].sectionData.blockType,
479                 qcOutChannel[0].windowShape,
480                 qcOutChannel[0].groupingMask,
481                 &(qcOutChannel[0].sectionData),
482                 hBitStream);
483 
484   encodeMSInfo(qcOutChannel[0].sectionData.sfbCnt,
485                qcOutChannel[0].sectionData.sfbPerGroup,
486                qcOutChannel[0].sectionData.maxSfbPerGroup,
487                msDigest,
488                msFlags,
489                hBitStream);
490 
491   writeIndividualChannelStream(1,
492                                qcOutChannel[0].mdctScale,
493                                qcOutChannel[0].windowShape,
494                                qcOutChannel[0].groupingMask,
495                                sfbOffset[0],
496                                qcOutChannel[0].scf,
497                                qcOutChannel[0].maxValueInSfb,
498                                qcOutChannel[0].globalGain,
499                                qcOutChannel[0].quantSpec,
500                                &(qcOutChannel[0].sectionData),
501                                hBitStream,
502                                tnsInfo[0]);
503 
504   writeIndividualChannelStream(1,
505                                qcOutChannel[1].mdctScale,
506                                qcOutChannel[1].windowShape,
507                                qcOutChannel[1].groupingMask,
508                                sfbOffset[1],
509                                qcOutChannel[1].scf,
510                                qcOutChannel[1].maxValueInSfb,
511                                qcOutChannel[1].globalGain,
512                                qcOutChannel[1].quantSpec,
513                                &(qcOutChannel[1].sectionData),
514                                hBitStream,
515                                tnsInfo[1]);
516 
517   return(0);
518 }
519 
520 
521 
522 /*****************************************************************************
523 *
524 * function name: writeFillElement
525 * description:  write fill elements to bitstream
526 * returns:      none
527 *
528 *****************************************************************************/
writeFillElement(const UWord8 * ancBytes,Word16 totFillBits,HANDLE_BIT_BUF hBitStream)529 static void writeFillElement( const UWord8 *ancBytes,
530                               Word16 totFillBits,
531                               HANDLE_BIT_BUF hBitStream)
532 {
533   Word16 i;
534   Word16 cnt,esc_count;
535 
536   /*
537     Write fill Element(s):
538     amount of a fill element can be 7+X*8 Bits, X element of [0..270]
539   */
540 
541   while(totFillBits >= (3+4)) {
542     cnt = min(((totFillBits - (3+4)) >> 3), ((1<<4)-1));
543 
544     WriteBits(hBitStream,ID_FIL,3);
545     WriteBits(hBitStream,cnt,4);
546 
547     totFillBits = totFillBits - (3+4);
548 
549 
550     if (cnt == (1<<4)-1) {
551 
552       esc_count = min( ((totFillBits >> 3) - ((1<<4)-1)), (1<<8)-1);
553       WriteBits(hBitStream,esc_count,8);
554       totFillBits = (totFillBits - 8);
555       cnt = cnt + (esc_count - 1);
556     }
557 
558     for(i=0;i<cnt;i++) {
559 
560       if(ancBytes)
561         WriteBits(hBitStream, *ancBytes++,8);
562       else
563         WriteBits(hBitStream,0,8);
564       totFillBits = totFillBits - 8;
565     }
566   }
567 }
568 
569 /*****************************************************************************
570 *
571 * function name: WriteBitStream
572 * description:  main function of write bitsteam process
573 * returns:      0 if success
574 *
575 *****************************************************************************/
WriteBitstream(HANDLE_BIT_BUF hBitStream,ELEMENT_INFO elInfo,QC_OUT * qcOut,PSY_OUT * psyOut,Word16 * globUsedBits,const UWord8 * ancBytes,Word16 sampindex)576 Word16 WriteBitstream (HANDLE_BIT_BUF hBitStream,
577                        ELEMENT_INFO elInfo,
578                        QC_OUT *qcOut,
579                        PSY_OUT *psyOut,
580                        Word16 *globUsedBits,
581                        const UWord8 *ancBytes,
582 					   Word16 sampindex
583                        ) /* returns error code */
584 {
585   Word16 bitMarkUp;
586   Word16 elementUsedBits;
587   Word16 frameBits=0;
588 
589   UNUSED(ancBytes);
590 
591   /*   struct bitbuffer bsWriteCopy; */
592   bitMarkUp = GetBitsAvail(hBitStream);
593   if(qcOut->qcElement.adtsUsed)  /*  write adts header*/
594   {
595 	  WriteBits(hBitStream, 0xFFF, 12); /* 12 bit Syncword */
596 	  WriteBits(hBitStream, 1, 1); /* ID == 0 for MPEG4 AAC, 1 for MPEG2 AAC */
597 	  WriteBits(hBitStream, 0, 2); /* layer == 0 */
598 	  WriteBits(hBitStream, 1, 1); /* protection absent */
599 	  WriteBits(hBitStream, 1, 2); /* profile */
600 	  WriteBits(hBitStream, sampindex, 4); /* sampling rate */
601 	  WriteBits(hBitStream, 0, 1); /* private bit */
602 	  WriteBits(hBitStream, elInfo.nChannelsInEl, 3); /* ch. config (must be > 0) */
603 								   /* simply using numChannels only works for
604 									6 channels or less, else a channel
605 									configuration should be written */
606 	  WriteBits(hBitStream, 0, 1); /* original/copy */
607 	  WriteBits(hBitStream, 0, 1); /* home */
608 
609 	  /* Variable ADTS header */
610 	  WriteBits(hBitStream, 0, 1); /* copyr. id. bit */
611 	  WriteBits(hBitStream, 0, 1); /* copyr. id. start */
612 	  WriteBits(hBitStream, *globUsedBits >> 3, 13);
613 	  WriteBits(hBitStream, 0x7FF, 11); /* buffer fullness (0x7FF for VBR) */
614 	  WriteBits(hBitStream, 0, 2); /* raw data blocks (0+1=1) */
615   }
616 
617   *globUsedBits=0;
618 
619   {
620 
621     Word16 *sfbOffset[2];
622     TNS_INFO tnsInfo[2];
623     elementUsedBits = 0;
624 
625     switch (elInfo.elType) {
626 
627       case ID_SCE:      /* single channel */
628         sfbOffset[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets;
629         tnsInfo[0] = psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo;
630 
631         writeSingleChannelElement(elInfo.instanceTag,
632                                   sfbOffset[0],
633                                   &qcOut->qcChannel[elInfo.ChannelIndex[0]],
634                                   hBitStream,
635                                   tnsInfo[0]);
636         break;
637 
638       case ID_CPE:     /* channel pair */
639         {
640           Word16 msDigest;
641           Word16 *msFlags = psyOut->psyOutElement.toolsInfo.msMask;
642           msDigest = psyOut->psyOutElement.toolsInfo.msDigest;
643           sfbOffset[0] =
644             psyOut->psyOutChannel[elInfo.ChannelIndex[0]].sfbOffsets;
645           sfbOffset[1] =
646             psyOut->psyOutChannel[elInfo.ChannelIndex[1]].sfbOffsets;
647 
648           tnsInfo[0]=
649             psyOut->psyOutChannel[elInfo.ChannelIndex[0]].tnsInfo;
650           tnsInfo[1]=
651             psyOut->psyOutChannel[elInfo.ChannelIndex[1]].tnsInfo;
652           writeChannelPairElement(elInfo.instanceTag,
653                                   msDigest,
654                                   msFlags,
655                                   sfbOffset,
656                                   &qcOut->qcChannel[elInfo.ChannelIndex[0]],
657                                   hBitStream,
658                                   tnsInfo);
659         }
660         break;
661 
662       default:
663         return(1);
664 
665       }   /* switch */
666 
667     elementUsedBits = elementUsedBits - bitMarkUp;
668     bitMarkUp = GetBitsAvail(hBitStream);
669     frameBits = frameBits + elementUsedBits + bitMarkUp;
670 
671   }
672 
673   writeFillElement(NULL,
674                    qcOut->totFillBits,
675                    hBitStream);
676 
677   WriteBits(hBitStream,ID_END,3);
678 
679   /* byte alignement */
680   WriteBits(hBitStream,0, (8 - (hBitStream->cntBits & 7)) & 7);
681 
682   *globUsedBits = *globUsedBits- bitMarkUp;
683   bitMarkUp = GetBitsAvail(hBitStream);
684   *globUsedBits = *globUsedBits + bitMarkUp;
685   frameBits = frameBits + *globUsedBits;
686 
687 
688   if (frameBits !=  (qcOut->totStaticBitsUsed+qcOut->totDynBitsUsed + qcOut->totAncBitsUsed +
689                      qcOut->totFillBits + qcOut->alignBits)) {
690     return(-1);
691   }
692   return(0);
693 }
694