/* (c) Copyright 1998-2001 - Tord Jansson ====================================== This file is part of the BladeEnc MP3 Encoder, based on ISO's reference code for MPEG Layer 3 compression. This file doesn't contain any of the ISO reference code and is copyright Tord Jansson (tord.jansson@swipnet.se). BladeEnc is free software; you can redistribute this file and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. ------------ Changes ------------ 2000-12-05 Andre Piotrowski - reformatted, slightly optimized 2001-01-12 ap - use some explicit type casting to avoid compiler warnings */ #include #include #if defined(_MSC) #include #endif #include "common.h" #include "formatbitstream2.h" extern char *pEncodedOutput; extern int outputBit; /*____ Structure Definitions _________________________________________________*/ typedef struct HeaderDef { int size; int frameSize; char data[128]; struct HeaderDef *pNext; } Header; /*____ Function Prototypes ___________________________________________________*/ static int writeMainDataBits (BF_FrameData *psFrame, BitHolder *psBH); static void putbits (unsigned int val, int n); static int generateHeader (BF_FrameData *psFrame); /*____ Static Data ___________________________________________________________*/ static int BitsRemaining = 0; static Header *pHeaderChain = NULL; static Header *pFreeHeaderChain = NULL; /*____ initFormatBitstream() ________________________________________________*/ void initFormatBitstream (void) { BitsRemaining = 0; pHeaderChain = NULL; pFreeHeaderChain = NULL; } /*____ exitFormatBitstream() _________________________________________________*/ void exitFormatBitstream (void) { Header *psFree; /* Fill out the last frame with 0xFF */ flushFrame (); /* Dealocate Headers */ while (pHeaderChain != NULL) { psFree = pHeaderChain; pHeaderChain = psFree->pNext; free (psFree); } while (pFreeHeaderChain != NULL) { psFree = pFreeHeaderChain; pFreeHeaderChain = psFree->pNext; free (psFree); } } /*____ flushFrame() _________________________________________________________*/ void flushFrame (void) { /* Fill out the last frame with 0xFF */ while (BitsRemaining > 32) { putbits (0xFFFFFFFF, 32); BitsRemaining -= 32; } if (BitsRemaining > 0) putbits (0xFFFFFFFF, BitsRemaining); BitsRemaining = 0; } /*____ initBitHolder() ______________________________________________________*/ BitHolder *initBitHolder ( BitHolder *wp, int elements ) { wp->element = (BitHolderElement *) malloc (sizeof(BitHolderElement) * elements); wp->max_elements = elements; wp->nrEntries = 0; return wp; } /*____ exitBitHolder() ______________________________________________________*/ void exitBitHolder (BitHolder * wp) { mem_free ((void **)&wp->element); /* if (wp->element != NULL) { free (wp->element); wp->element = NULL; } */ } /*____ addBits() ____________________________________________________________*/ void addBits ( BitHolder *wp, unsigned int value, int length ) { if (length != 0) { if (wp->nrEntries == wp->max_elements) { printf ("ERROR: BitHolder overflow!\n"); exit (-1); } value &= 0xFFFFFFFF >> (32-length); wp->element[wp->nrEntries].value = value; wp->element[wp->nrEntries].length = length; wp->nrEntries++; } } /*____ writeFrame() _________________________________________________________*/ void writeFrame ( BF_FrameData *psFrame, BF_FrameResults *results ) { int bits; int gr, ch; int sizeRemainHeaders, sizeRemainFrames; Header *psHeader; /* Generate and save header, return size of SideInfo.*/ results->SILength = generateHeader (psFrame); /* Put the bits and compute size of mainData */ bits = 0; for (gr = 0; gr < psFrame->nGranules; gr++) { for (ch = 0; ch < psFrame->nChannels; ch++) { bits += writeMainDataBits (psFrame, &psFrame->scaleFactors[gr][ch]); bits += writeMainDataBits (psFrame, &psFrame-> codedData[gr][ch]); bits += writeMainDataBits (psFrame, &psFrame->userSpectrum[gr][ch]); } } bits += writeMainDataBits (psFrame, &psFrame->userFrameData); results->mainDataLength = bits; /* calculate nextBackPointer */ sizeRemainHeaders = 0; sizeRemainFrames = 0; for (psHeader = pHeaderChain; psHeader != NULL; psHeader = psHeader->pNext) { sizeRemainHeaders += psHeader->size; sizeRemainFrames += psHeader->frameSize; } results->nextBackPtr = (BitsRemaining / 8) + sizeRemainFrames - sizeRemainHeaders; /* BitsRemaining must be dividable by 8 */ } /*============================================================================= >>> Static Functions <<< =============================================================================*/ /*____ writeBitHolder() _____________________________________________________*/ static void writeBitHolder (BitHolder *part) { BitHolderElement *ep; int i; ep = part->element; for (i = 0; i < part->nrEntries; i++, ep++) putbits (ep->value, ep->length); } /*____ calcCRC() ____________________________________________________________*/ static int calcCRC ( char *pData, int size ) { int i; int crc = 0xffff; int masking; int carry; int data; for (i = 2; i < size; i++) { if (i != 4 && i != 5) { masking = 1 << 8; data = pData[i]; while (masking >>= 1) { carry = crc & 0x8000; crc <<= 1; /* if ( (carry == 0) != ((data & masking) == 0) ) */ if (!carry ^ !(data & masking)) crc ^= 0x8005; } } } crc &= 0xffff; return crc; } /*____ generateHeader() ____________________________________________________*/ static int generateHeader (BF_FrameData *psFrame) { int gr, ch; int crc; Header *psHeader; Header **wpLink; char *pOldEncodedOutput; /* Get a Free Header structure */ if( pFreeHeaderChain == NULL ) psHeader = (Header *) malloc( sizeof( Header ) ); else { psHeader = pFreeHeaderChain; pFreeHeaderChain = psHeader->pNext; } psHeader->pNext = NULL; for( wpLink = &pHeaderChain ; * wpLink != NULL ; wpLink = &((*wpLink)->pNext) ) {} /* avoid compiler warning */ *wpLink = psHeader; /* Generate the Header */ pOldEncodedOutput = pEncodedOutput; pEncodedOutput = psHeader->data; pEncodedOutput[0] = 0; /* Need to be cleared since we OR in data... */ writeBitHolder (&psFrame->header); writeBitHolder (&psFrame->frameSI); for (ch = 0; ch < psFrame->nChannels; ch++) writeBitHolder (&psFrame->channelSI[ch]); for (gr = 0; gr < psFrame->nGranules; gr++) for (ch = 0; ch < psFrame->nChannels; ch++) writeBitHolder (&psFrame->spectrumSI[gr][ch]); /* Checksum generation (if CRC enabled).*/ if (!(psHeader->data[1] & 0x1)) { crc = calcCRC (psHeader->data, pEncodedOutput - psHeader->data); psHeader->data[4] = (char) (crc >> 8); psHeader->data[5] = (char) crc; } psHeader->size = pEncodedOutput - psHeader->data; psHeader->frameSize = psFrame->frameLength / 8; pEncodedOutput = pOldEncodedOutput; return psHeader->size * 8; } /*____ writeHeader() _______________________________________________________*/ static int writeHeader (void) { Header *psHeader; psHeader = pHeaderChain; memcpy (pEncodedOutput, psHeader->data, psHeader->size); pEncodedOutput += psHeader->size; *pEncodedOutput = 0; pHeaderChain = psHeader->pNext; psHeader->pNext = pFreeHeaderChain; pFreeHeaderChain = psHeader; return (psHeader->frameSize - psHeader->size) * 8; } /*____ writeMainDataBits() __________________________________________________*/ static int writeMainDataBits ( BF_FrameData *psFrame, /* avoid compiler warning */ BitHolder *psBH ) { BitHolderElement *psElem = psBH->element; int i, bits = 0; unsigned int val; int nBits; for (i = 0; i < psBH->nrEntries; i++, psElem++) { val = psElem->value; nBits = psElem->length; if (BitsRemaining == 0) BitsRemaining = writeHeader (); if (nBits > BitsRemaining) { nBits -= BitsRemaining; putbits (val >> nBits, BitsRemaining); BitsRemaining = writeHeader (); } putbits (val, nBits); BitsRemaining -= nBits; bits += psElem->length; } return bits; } /*____ putbits() _____________________________________________________________*/ /*write n bits into the bit stream */ static void putbits ( unsigned int val, int n ) { if (n == 0) return; while (n >= outputBit) { n -= outputBit; *pEncodedOutput |= val >> n; outputBit = 8; pEncodedOutput++; *pEncodedOutput = 0; } if (n > 0) /* n < outputBit */ { outputBit -= n; *pEncodedOutput |= val << outputBit; } }