mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-06-25 19:53:05 +00:00
1343 lines
45 KiB
C
1343 lines
45 KiB
C
/*
|
|
* Copyright (c) 2011 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2012-2013 Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
*
|
|
* @APPLE_APACHE_LICENSE_HEADER_START@
|
|
*
|
|
* 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.
|
|
*
|
|
* @APPLE_APACHE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
/*
|
|
File: ALACEncoder.cpp
|
|
*/
|
|
|
|
// build stuff
|
|
#define VERBOSE_DEBUG 0
|
|
#define DebugMsg printf
|
|
|
|
// headers
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "sfendian.h"
|
|
|
|
#include "alac_codec.h"
|
|
|
|
#include "aglib.h"
|
|
#include "dplib.h"
|
|
#include "matrixlib.h"
|
|
|
|
#include "ALACBitUtilities.h"
|
|
#include "ALACAudioTypes.h"
|
|
#include "EndianPortable.h"
|
|
|
|
typedef enum
|
|
{
|
|
false = 0,
|
|
true = 1
|
|
} bool ;
|
|
|
|
static void GetConfig(ALAC_ENCODER *p, ALACSpecificConfig * config );
|
|
|
|
static int32_t EncodeStereo(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
|
|
static int32_t EncodeStereoFast(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
|
|
static int32_t EncodeStereoEscape(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * input, uint32_t stride, uint32_t numSamples );
|
|
static int32_t EncodeMono(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
|
|
|
|
|
|
|
|
// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when
|
|
// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type
|
|
typedef int16_t (*SearchCoefs)[kALACMaxCoefs];
|
|
|
|
// defines/constants
|
|
const uint32_t kALACEncoderMagic = MAKE_MARKER ('d', 'p', 'g', 'e');
|
|
const uint32_t kMaxSampleSize = 32; // max allowed bit width is 32
|
|
const uint32_t kDefaultMixBits = 2;
|
|
const uint32_t kDefaultMixRes = 0;
|
|
const uint32_t kMaxRes = 4;
|
|
const uint32_t kDefaultNumUV = 8;
|
|
const uint32_t kMinUV = 4;
|
|
const uint32_t kMaxUV = 8;
|
|
|
|
// static functions
|
|
#if VERBOSE_DEBUG
|
|
static void AddFiller( BitBuffer * bits, int32_t numBytes );
|
|
#endif
|
|
|
|
|
|
/*
|
|
Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed
|
|
at the beginning of the frame for that channel. Indicates whether SCE, CPE, or LFE.
|
|
Each particular field is accessed via the current channel indx. Note that the channel
|
|
indx increments by two for channel pairs.
|
|
|
|
For example:
|
|
|
|
C L R 3-channel input = (ID_CPE << 3) | (ID_SCE)
|
|
indx 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
|
|
indx 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
|
|
|
|
C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
|
|
indx 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
|
|
indx 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
|
|
indx 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3)
|
|
indx 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3)
|
|
indx 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3)
|
|
*/
|
|
static const uint32_t sChannelMaps[kALACMaxChannels] =
|
|
{
|
|
ID_SCE,
|
|
ID_CPE,
|
|
(ID_CPE << 3) | (ID_SCE),
|
|
(ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE),
|
|
(ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
|
|
(ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
|
|
(ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
|
|
(ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
|
|
};
|
|
|
|
static const uint32_t sSupportediPodSampleRates[] =
|
|
{
|
|
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
|
|
};
|
|
|
|
|
|
#if PRAGMA_MARK
|
|
#pragma mark -
|
|
#endif
|
|
|
|
void
|
|
alac_set_fastmode (ALAC_ENCODER * p, int32_t fast )
|
|
{
|
|
p->mFastMode = fast;
|
|
}
|
|
|
|
|
|
/*
|
|
HEADER SPECIFICATION
|
|
|
|
For every segment we adopt the following header:
|
|
|
|
1 byte reserved (always 0)
|
|
1 byte flags (see below)
|
|
[4 byte frame length] (optional, see below)
|
|
---Next, the per-segment ALAC parameters---
|
|
1 byte mixBits (middle-side parameter)
|
|
1 byte mixRes (middle-side parameter, interpreted as signed char)
|
|
|
|
1 byte shiftU (4 bits modeU, 4 bits denShiftU)
|
|
1 byte filterU (3 bits pbFactorU, 5 bits numU)
|
|
(numU) shorts (signed DP coefficients for V channel)
|
|
---Next, 2nd-channel ALAC parameters in case of stereo mode---
|
|
1 byte shiftV (4 bits modeV, 4 bits denShiftV)
|
|
1 byte filterV (3 bits pbFactorV, 5 bits numV)
|
|
(numV) shorts (signed DP coefficients for V channel)
|
|
---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated---
|
|
---Then comes the AG-compressor bitstream---
|
|
|
|
|
|
FLAGS
|
|
-----
|
|
|
|
The presence of certain flag bits changes the header format such that the parameters might
|
|
not even be sent. The currently defined flags format is:
|
|
|
|
0000psse
|
|
|
|
where 0 = reserved, must be 0
|
|
p = 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte
|
|
ss = 2-bit field indicating "number of shift-off bytes ignored by compression"
|
|
e = 1-bit field indicating "escape"
|
|
|
|
The "partial frame" flag means that the following segment is not equal to the frame length specified
|
|
in the out-of-band decoder configuration. This allows the decoder to deal with end-of-file partial
|
|
segments without incurring the 32-bit overhead for each segment.
|
|
|
|
The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through
|
|
uncompressed. The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words
|
|
quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the
|
|
uncompressed size. However, by shifting the input values down and running the remaining bits through
|
|
the normal compression algorithm, a net win can be achieved. If this field is non-zero, it means that
|
|
the shifted-off bytes follow after the parameter section of the header and before the compressed
|
|
bitstream. Note that doing this also allows us to use matrixing on 32-bit inputs after one or more
|
|
bytes are shifted off the bottom which helps the eventual compression ratio. For stereo channels,
|
|
the shifted off bytes are interleaved.
|
|
|
|
The "escape" flag means that this segment was not compressed b/c the compressed size would be
|
|
>= uncompressed size. In that case, the audio data was passed through uncompressed after the header.
|
|
The other header parameter bytes will not be sent.
|
|
|
|
|
|
PARAMETERS
|
|
----------
|
|
|
|
If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by:
|
|
|
|
4 + (2 + 2 * numU) (mono mode)
|
|
4 + (2 + 2 * numV) + (2 + 2 * numV) (stereo mode)
|
|
|
|
where the ALAC filter-lengths numU, numV are bounded by a
|
|
constant (in the current source, numU, numV <= NUMCOEPAIRS), and
|
|
this forces an absolute upper bound on header size.
|
|
|
|
Each segment-decode process loads up these bytes from the front of the
|
|
local stream, in the above order, then follows with the entropy-encoded
|
|
bits for the given segment.
|
|
|
|
To generalize middle-side, there are various mixing modes including middle-side, each lossless,
|
|
as embodied in the mix() and unmix() functions. These functions exploit a generalized middle-side
|
|
transformation:
|
|
|
|
u := [(rL + (m-r)R)/m];
|
|
v := L - R;
|
|
|
|
where [ ] denotes integer floor. The (lossless) inverse is
|
|
|
|
L = u + v - [rV/m];
|
|
R = L - v;
|
|
|
|
In the segment header, m and r are encoded in mixBits and mixRes.
|
|
Classical "middle-side" is obtained with m = 2, r = 1, but now
|
|
we have more generalized mixes.
|
|
|
|
NOTES
|
|
-----
|
|
The relevance of the ALAC coefficients is explained in detail
|
|
in patent documents.
|
|
*/
|
|
|
|
/*
|
|
EncodeStereo()
|
|
- encode a channel pair
|
|
*/
|
|
static int32_t
|
|
EncodeStereo(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
|
|
{
|
|
BitBuffer workBits;
|
|
BitBuffer startBits = *bitstream; // squirrel away copy of current state in case we need to go back and do an escape packet
|
|
AGParamRec agParams;
|
|
uint32_t bits1, bits2;
|
|
uint32_t dilate;
|
|
int32_t mixBits, mixRes, maxRes;
|
|
uint32_t minBits, minBits1, minBits2;
|
|
uint32_t numU, numV;
|
|
uint32_t mode;
|
|
uint32_t pbFactor;
|
|
uint32_t chanBits;
|
|
uint8_t bytesShifted;
|
|
SearchCoefs coefsU;
|
|
SearchCoefs coefsV;
|
|
uint32_t indx;
|
|
uint8_t partialFrame;
|
|
uint32_t escapeBits;
|
|
bool doEscape;
|
|
int32_t status = ALAC_noErr;
|
|
int32_t bestRes;
|
|
uint32_t numUV, converge;
|
|
|
|
// make sure we handle this bit-depth before we get going
|
|
RequireAction( (p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError; );
|
|
|
|
// reload coefs pointers for this channel pair
|
|
// - note that, while you might think they should be re-initialized per block, retaining state across blocks
|
|
// actually results in better overall compression
|
|
// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
|
|
// different coefs for the different passes of "mixRes" results in even better compression
|
|
coefsU = (SearchCoefs) p->mCoefsU[channelIndex];
|
|
coefsV = (SearchCoefs) p->mCoefsV[channelIndex];
|
|
|
|
// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
|
|
// so enable 16-bit "shift off" and encode in 17-bit mode
|
|
// - in addition, 24-bit mode really improves with one byte shifted off
|
|
if ( p->mBitDepth == 32 )
|
|
bytesShifted = 2;
|
|
else if ( p->mBitDepth >= 24 )
|
|
bytesShifted = 1;
|
|
else
|
|
bytesShifted = 0;
|
|
|
|
chanBits = p->mBitDepth - (bytesShifted * 8) + 1;
|
|
|
|
// flag whether or not this is a partial frame
|
|
partialFrame = (numSamples == p->mFrameSize) ? 0 : 1;
|
|
|
|
// brute-force encode optimization loop
|
|
// - run over variations of the encoding params to find the best choice
|
|
mixBits = kDefaultMixBits;
|
|
maxRes = kMaxRes;
|
|
numU = numV = kDefaultNumUV;
|
|
mode = 0;
|
|
pbFactor = 4;
|
|
dilate = 8;
|
|
|
|
minBits = minBits1 = minBits2 = 1ul << 31;
|
|
|
|
bestRes = p->mLastMixRes[channelIndex];
|
|
|
|
for ( mixRes = 0; mixRes <= maxRes; mixRes++ )
|
|
{
|
|
// mix the stereo inputs
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
mix16( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples/dilate, mixBits, mixRes );
|
|
break;
|
|
case 20:
|
|
mix20( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples/dilate, mixBits, mixRes );
|
|
break;
|
|
case 24:
|
|
// includes extraction of shifted-off bytes
|
|
mix24( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples/dilate,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
case 32:
|
|
// includes extraction of shifted-off bytes
|
|
mix32( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples/dilate,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
}
|
|
|
|
BitBufferInit( &workBits, p->mWorkBuffer, p->mMaxOutputBytes );
|
|
|
|
// run the dynamic predictors
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples/dilate, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
pc_block( p->mMixBufferV, p->mPredictorV, numSamples/dilate, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
// run the lossless compressor on each channel
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
// look for best match
|
|
if ( (bits1 + bits2) < minBits1 )
|
|
{
|
|
minBits1 = bits1 + bits2;
|
|
bestRes = mixRes;
|
|
}
|
|
}
|
|
|
|
p->mLastMixRes[channelIndex] = (int16_t)bestRes;
|
|
|
|
// mix the stereo inputs with the current best mixRes
|
|
mixRes = p->mLastMixRes[channelIndex];
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
mix16( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes );
|
|
break;
|
|
case 20:
|
|
mix20( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes );
|
|
break;
|
|
case 24:
|
|
// also extracts the shifted off bytes into the shift buffers
|
|
mix24( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
case 32:
|
|
// also extracts the shifted off bytes into the shift buffers
|
|
mix32( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
}
|
|
|
|
// now it's time for the predictor coefficient search loop
|
|
numU = numV = kMinUV;
|
|
minBits1 = minBits2 = 1ul << 31;
|
|
|
|
for ( numUV = kMinUV; numUV <= kMaxUV; numUV += 4 )
|
|
{
|
|
BitBufferInit( &workBits, p->mWorkBuffer, p->mMaxOutputBytes );
|
|
|
|
dilate = 32;
|
|
|
|
// run the predictor over the same data multiple times to help it converge
|
|
for ( converge = 0; converge < 8; converge++ )
|
|
{
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples/dilate, coefsU[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
|
|
pc_block( p->mMixBufferV, p->mPredictorV, numSamples/dilate, coefsV[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
|
|
}
|
|
|
|
dilate = 8;
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
|
|
|
|
if ( (bits1 * dilate + 16 * numUV) < minBits1 )
|
|
{
|
|
minBits1 = bits1 * dilate + 16 * numUV;
|
|
numU = numUV;
|
|
}
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
|
|
|
|
if ( (bits2 * dilate + 16 * numUV) < minBits2 )
|
|
{
|
|
minBits2 = bits2 * dilate + 16 * numUV;
|
|
numV = numUV;
|
|
}
|
|
}
|
|
|
|
// test for escape hatch if best calculated compressed size turns out to be more than the input size
|
|
minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
|
|
if ( bytesShifted != 0 )
|
|
minBits += (numSamples * (bytesShifted * 8) * 2);
|
|
|
|
escapeBits = (numSamples * p->mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */
|
|
|
|
doEscape = (minBits >= escapeBits) ? true : false;
|
|
|
|
if ( doEscape == false )
|
|
{
|
|
// write bitstream header and coefs
|
|
BitBufferWrite( bitstream, 0, 12 );
|
|
BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
|
|
if ( partialFrame )
|
|
BitBufferWrite( bitstream, numSamples, 32 );
|
|
BitBufferWrite( bitstream, mixBits, 8 );
|
|
BitBufferWrite( bitstream, mixRes, 8 );
|
|
|
|
//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
|
|
//Assert( (pbFactor < 8) && (numU < 32) );
|
|
//Assert( (pbFactor < 8) && (numV < 32) );
|
|
|
|
BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
|
|
BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
|
|
for ( indx = 0; indx < numU; indx++ )
|
|
BitBufferWrite( bitstream, coefsU[numU - 1][indx], 16 );
|
|
|
|
BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
|
|
BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
|
|
for ( indx = 0; indx < numV; indx++ )
|
|
BitBufferWrite( bitstream, coefsV[numV - 1][indx], 16 );
|
|
|
|
// if shift active, write the interleaved shift buffers
|
|
if ( bytesShifted != 0 )
|
|
{
|
|
uint32_t bitShift = bytesShifted * 8;
|
|
|
|
//Assert( bitShift <= 16 );
|
|
|
|
for ( indx = 0; indx < (numSamples * 2); indx += 2 )
|
|
{
|
|
uint32_t shiftedVal;
|
|
|
|
shiftedVal = ((uint32_t) p->mShiftBufferUV[indx + 0] << bitShift) | (uint32_t) p->mShiftBufferUV[indx + 1];
|
|
BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
|
|
}
|
|
}
|
|
|
|
// run the dynamic predictor and lossless compression for the "left" channel
|
|
// - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead
|
|
// of only using "U" buffers for the U-channel and "V" buffers for the V-channel
|
|
if ( mode == 0 )
|
|
{
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
}
|
|
else
|
|
{
|
|
pc_block( p->mMixBufferU, p->mPredictorV, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
pc_block( p->mPredictorV, p->mPredictorU, numSamples, NULL, 31, chanBits, 0 );
|
|
}
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
// run the dynamic predictor and lossless compression for the "right" channel
|
|
if ( mode == 0 )
|
|
{
|
|
pc_block( p->mMixBufferV, p->mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
|
|
}
|
|
else
|
|
{
|
|
pc_block( p->mMixBufferV, p->mPredictorU, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
|
|
pc_block( p->mPredictorU, p->mPredictorV, numSamples, NULL, 31, chanBits, 0 );
|
|
}
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorV, bitstream, numSamples, chanBits, &bits2 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
/* if we happened to create a compressed packet that was actually bigger than an escape packet would be,
|
|
chuck it and do an escape packet
|
|
*/
|
|
minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
|
|
if ( minBits >= escapeBits )
|
|
{
|
|
*bitstream = startBits; // reset bitstream state
|
|
doEscape = true;
|
|
printf( "compressed frame too big: %u vs. %u \n", minBits, escapeBits );
|
|
}
|
|
}
|
|
|
|
if ( doEscape == true )
|
|
{
|
|
/* escape */
|
|
status = EncodeStereoEscape(p, bitstream, inputBuffer, stride, numSamples );
|
|
|
|
#if VERBOSE_DEBUG
|
|
DebugMsg( "escape!: %u vs %u\n", minBits, escapeBits );
|
|
#endif
|
|
}
|
|
|
|
Exit:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
EncodeStereoFast()
|
|
- encode a channel pair without the search loop for maximum possible speed
|
|
*/
|
|
static int32_t
|
|
EncodeStereoFast(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
|
|
{
|
|
BitBuffer startBits = *bitstream; // squirrel away current bit position in case we decide to use escape hatch
|
|
AGParamRec agParams;
|
|
uint32_t bits1, bits2;
|
|
int32_t mixBits, mixRes;
|
|
uint32_t minBits, minBits1, minBits2;
|
|
uint32_t numU, numV;
|
|
uint32_t mode;
|
|
uint32_t pbFactor;
|
|
uint32_t chanBits;
|
|
uint8_t bytesShifted;
|
|
SearchCoefs coefsU;
|
|
SearchCoefs coefsV;
|
|
uint32_t indx;
|
|
uint8_t partialFrame;
|
|
uint32_t escapeBits;
|
|
bool doEscape;
|
|
int32_t status;
|
|
|
|
// make sure we handle this bit-depth before we get going
|
|
RequireAction( (p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError; );
|
|
|
|
// reload coefs pointers for this channel pair
|
|
// - note that, while you might think they should be re-initialized per block, retaining state across blocks
|
|
// actually results in better overall compression
|
|
// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
|
|
// different coefs for the different passes of "mixRes" results in even better compression
|
|
coefsU = (SearchCoefs) p->mCoefsU[channelIndex];
|
|
coefsV = (SearchCoefs) p->mCoefsV[channelIndex];
|
|
|
|
// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
|
|
// so enable 16-bit "shift off" and encode in 17-bit mode
|
|
// - in addition, 24-bit mode really improves with one byte shifted off
|
|
if ( p->mBitDepth == 32 )
|
|
bytesShifted = 2;
|
|
else if ( p->mBitDepth >= 24 )
|
|
bytesShifted = 1;
|
|
else
|
|
bytesShifted = 0;
|
|
|
|
chanBits = p->mBitDepth - (bytesShifted * 8) + 1;
|
|
|
|
// flag whether or not this is a partial frame
|
|
partialFrame = (numSamples == p->mFrameSize) ? 0 : 1;
|
|
|
|
// set up default encoding parameters for "fast" mode
|
|
mixBits = kDefaultMixBits;
|
|
mixRes = kDefaultMixRes;
|
|
numU = numV = kDefaultNumUV;
|
|
mode = 0;
|
|
pbFactor = 4;
|
|
|
|
minBits = minBits1 = minBits2 = 1ul << 31;
|
|
|
|
// mix the stereo inputs with default mixBits/mixRes
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
mix16( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes );
|
|
break;
|
|
case 20:
|
|
mix20( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes );
|
|
break;
|
|
case 24:
|
|
// also extracts the shifted off bytes into the shift buffers
|
|
mix24( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
case 32:
|
|
// also extracts the shifted off bytes into the shift buffers
|
|
mix32( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples,
|
|
mixBits, mixRes, p->mShiftBufferUV, bytesShifted );
|
|
break;
|
|
}
|
|
|
|
/* speculatively write the bitstream assuming the compressed version will be smaller */
|
|
|
|
// write bitstream header and coefs
|
|
BitBufferWrite( bitstream, 0, 12 );
|
|
BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
|
|
if ( partialFrame )
|
|
BitBufferWrite( bitstream, numSamples, 32 );
|
|
BitBufferWrite( bitstream, mixBits, 8 );
|
|
BitBufferWrite( bitstream, mixRes, 8 );
|
|
|
|
//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
|
|
//Assert( (pbFactor < 8) && (numU < 32) );
|
|
//Assert( (pbFactor < 8) && (numV < 32) );
|
|
|
|
BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
|
|
BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
|
|
for ( indx = 0; indx < numU; indx++ )
|
|
BitBufferWrite( bitstream, coefsU[numU - 1][indx], 16 );
|
|
|
|
BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
|
|
BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
|
|
for ( indx = 0; indx < numV; indx++ )
|
|
BitBufferWrite( bitstream, coefsV[numV - 1][indx], 16 );
|
|
|
|
// if shift active, write the interleaved shift buffers
|
|
if ( bytesShifted != 0 )
|
|
{
|
|
uint32_t bitShift = bytesShifted * 8;
|
|
|
|
//Assert( bitShift <= 16 );
|
|
|
|
for ( indx = 0; indx < (numSamples * 2); indx += 2 )
|
|
{
|
|
uint32_t shiftedVal;
|
|
|
|
shiftedVal = ((uint32_t) p->mShiftBufferUV[indx + 0] << bitShift) | (uint32_t) p->mShiftBufferUV[indx + 1];
|
|
BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
|
|
}
|
|
}
|
|
|
|
// run the dynamic predictor and lossless compression for the "left" channel
|
|
// - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
// run the dynamic predictor and lossless compression for the "right" channel
|
|
pc_block( p->mMixBufferV, p->mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorV, bitstream, numSamples, chanBits, &bits2 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
// do bit requirement calculations
|
|
minBits1 = bits1 + (numU * sizeof(int16_t) * 8);
|
|
minBits2 = bits2 + (numV * sizeof(int16_t) * 8);
|
|
|
|
// test for escape hatch if best calculated compressed size turns out to be more than the input size
|
|
minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
|
|
if ( bytesShifted != 0 )
|
|
minBits += (numSamples * (bytesShifted * 8) * 2);
|
|
|
|
escapeBits = (numSamples * p->mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */
|
|
|
|
doEscape = (minBits >= escapeBits) ? true : false;
|
|
|
|
if ( doEscape == false )
|
|
{
|
|
/* if we happened to create a compressed packet that was actually bigger than an escape packet would be,
|
|
chuck it and do an escape packet
|
|
*/
|
|
minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
|
|
if ( minBits >= escapeBits )
|
|
{
|
|
doEscape = true;
|
|
printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits );
|
|
}
|
|
|
|
}
|
|
|
|
if ( doEscape == true )
|
|
{
|
|
/* escape */
|
|
|
|
// reset bitstream position since we speculatively wrote the compressed version
|
|
*bitstream = startBits;
|
|
|
|
// write escape frame
|
|
status = EncodeStereoEscape(p, bitstream, inputBuffer, stride, numSamples );
|
|
|
|
#if VERBOSE_DEBUG
|
|
DebugMsg( "escape!: %u vs %u\n", minBits, (numSamples * p->mBitDepth * 2) );
|
|
#endif
|
|
}
|
|
|
|
Exit:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
EncodeStereoEscape()
|
|
- encode stereo escape frame
|
|
*/
|
|
static int32_t
|
|
EncodeStereoEscape(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * inputBuffer, uint32_t stride, uint32_t numSamples )
|
|
{
|
|
uint8_t partialFrame;
|
|
uint32_t indx;
|
|
|
|
// flag whether or not this is a partial frame
|
|
partialFrame = (numSamples == p->mFrameSize) ? 0 : 1;
|
|
|
|
// write bitstream header
|
|
BitBufferWrite( bitstream, 0, 12 );
|
|
BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 ); // LSB = 1 means "frame not compressed"
|
|
if ( partialFrame )
|
|
BitBufferWrite( bitstream, numSamples, 32 );
|
|
|
|
// just copy the input data to the output buffer
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
{
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 0] >> 16, 16 );
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 1] >> 16, 16 );
|
|
}
|
|
break;
|
|
case 20:
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
{
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 0] >> 12, 16 );
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 1] >> 12, 16 );
|
|
}
|
|
break;
|
|
case 24:
|
|
// mix24() with mixres param = 0 means de-interleave so use it to simplify things
|
|
mix24( inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, 0, 0, p->mShiftBufferUV, 0 );
|
|
for ( indx = 0; indx < numSamples; indx++ )
|
|
{
|
|
BitBufferWrite( bitstream, p->mMixBufferU[indx] >> 8, 24 );
|
|
BitBufferWrite( bitstream, p->mMixBufferV[indx] >> 8, 24 );
|
|
}
|
|
break;
|
|
case 32:
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
{
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 0], 32 );
|
|
BitBufferWrite( bitstream, inputBuffer[indx + 1], 32 );
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ALAC_noErr;
|
|
}
|
|
|
|
/*
|
|
EncodeMono()
|
|
- encode a mono input buffer
|
|
*/
|
|
static int32_t
|
|
EncodeMono(ALAC_ENCODER *p, struct BitBuffer * bitstream, int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
|
|
{
|
|
BitBuffer startBits = *bitstream; // squirrel away copy of current state in case we need to go back and do an escape packet
|
|
AGParamRec agParams;
|
|
uint32_t bits1;
|
|
uint32_t numU;
|
|
SearchCoefs coefsU;
|
|
uint32_t dilate;
|
|
uint32_t minBits, bestU;
|
|
uint32_t minU, maxU;
|
|
uint32_t indx, indx2;
|
|
uint8_t bytesShifted;
|
|
uint32_t shift;
|
|
uint32_t mask;
|
|
uint32_t chanBits;
|
|
uint8_t pbFactor;
|
|
uint8_t partialFrame;
|
|
uint32_t escapeBits;
|
|
bool doEscape;
|
|
int32_t status = ALAC_noErr;
|
|
uint32_t converge;
|
|
|
|
|
|
// make sure we handle this bit-depth before we get going
|
|
RequireAction( (p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError; );
|
|
|
|
// reload coefs array from previous frame
|
|
coefsU = (SearchCoefs) p->mCoefsU[channelIndex];
|
|
|
|
// pick bit depth for actual encoding
|
|
// - we lop off the lower byte(s) for 24-/32-bit encodings
|
|
if ( p->mBitDepth == 32 )
|
|
bytesShifted = 2;
|
|
else if ( p->mBitDepth >= 24 )
|
|
bytesShifted = 1;
|
|
else
|
|
bytesShifted = 0;
|
|
|
|
shift = bytesShifted * 8;
|
|
mask = (1ul << shift) - 1;
|
|
chanBits = p->mBitDepth - (bytesShifted * 8);
|
|
|
|
// flag whether or not this is a partial frame
|
|
partialFrame = (numSamples == p->mFrameSize) ? 0 : 1;
|
|
|
|
// convert N-bit data to 32-bit for predictor
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
// convert 16-bit data to 32-bit for predictor
|
|
for ( indx = 0, indx2 = 0; indx < numSamples; indx++, indx2 += stride )
|
|
p->mMixBufferU[indx] = inputBuffer[indx2] >> 16;
|
|
break;
|
|
|
|
case 20:
|
|
// convert 20-bit data to 32-bit for predictor
|
|
for ( indx = 0, indx2 = 0; indx < numSamples; indx++, indx2 += stride )
|
|
p->mMixBufferU[indx] = inputBuffer[indx2] >> 12;
|
|
break;
|
|
case 24:
|
|
// convert 24-bit data to 32-bit for the predictor and extract the shifted off byte(s)
|
|
for ( indx = 0, indx2 = 0; indx < numSamples; indx++, indx2 += stride )
|
|
{
|
|
p->mMixBufferU[indx] = inputBuffer[indx2] >> 8;
|
|
p->mShiftBufferUV[indx] = (uint16_t)(p->mMixBufferU[indx] & mask);
|
|
p->mMixBufferU[indx] >>= shift;
|
|
}
|
|
|
|
break;
|
|
case 32:
|
|
// just copy the 32-bit input data for the predictor and extract the shifted off byte(s)
|
|
for ( indx = 0, indx2 = 0; indx < numSamples; indx++, indx2 += stride )
|
|
{
|
|
p->mShiftBufferUV[indx] = (uint16_t)(inputBuffer[indx2] & mask);
|
|
p->mMixBufferU[indx] = inputBuffer[indx2] >> shift;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool)
|
|
// - run over variations of the encoding params to find the best choice
|
|
minU = 4;
|
|
maxU = 8;
|
|
minBits = 1ul << 31;
|
|
pbFactor = 4;
|
|
|
|
bestU = minU;
|
|
|
|
for ( numU = minU; numU <= maxU; numU += 4 )
|
|
{
|
|
BitBuffer workBits;
|
|
uint32_t numBits;
|
|
|
|
BitBufferInit( &workBits, p->mWorkBuffer, p->mMaxOutputBytes );
|
|
|
|
dilate = 32;
|
|
for ( converge = 0; converge < 7; converge++ )
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
dilate = 8;
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
|
|
status = dyn_comp( &agParams, p->mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
|
|
RequireNoErr( status, goto Exit; );
|
|
|
|
numBits = (dilate * bits1) + (16 * numU);
|
|
if ( numBits < minBits )
|
|
{
|
|
bestU = numU;
|
|
minBits = numBits;
|
|
}
|
|
}
|
|
|
|
// test for escape hatch if best calculated compressed size turns out to be more than the input size
|
|
// - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU
|
|
minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
|
|
if ( bytesShifted != 0 )
|
|
minBits += (numSamples * (bytesShifted * 8));
|
|
|
|
escapeBits = (numSamples * p->mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */
|
|
|
|
doEscape = (minBits >= escapeBits) ? true : false;
|
|
|
|
if ( doEscape == false )
|
|
{
|
|
// write bitstream header
|
|
BitBufferWrite( bitstream, 0, 12 );
|
|
BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
|
|
if ( partialFrame )
|
|
BitBufferWrite( bitstream, numSamples, 32 );
|
|
BitBufferWrite( bitstream, 0, 16 ); // mixBits = mixRes = 0
|
|
|
|
// write the params and predictor coefs
|
|
numU = bestU;
|
|
BitBufferWrite( bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8 ); // modeU = 0
|
|
BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
|
|
for ( indx = 0; indx < numU; indx++ )
|
|
BitBufferWrite( bitstream, coefsU[numU-1][indx], 16 );
|
|
|
|
// if shift active, write the interleaved shift buffers
|
|
if ( bytesShifted != 0 )
|
|
{
|
|
for ( indx = 0; indx < numSamples; indx++ )
|
|
BitBufferWrite( bitstream, p->mShiftBufferUV[indx], shift );
|
|
}
|
|
|
|
// run the dynamic predictor with the best result
|
|
pc_block( p->mMixBufferU, p->mPredictorU, numSamples, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
|
|
|
|
// do lossless compression
|
|
set_standard_ag_params( &agParams, numSamples, numSamples );
|
|
status = dyn_comp( &agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1 );
|
|
//AssertNoErr( status );
|
|
|
|
|
|
/* if we happened to create a compressed packet that was actually bigger than an escape packet would be,
|
|
chuck it and do an escape packet
|
|
*/
|
|
minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
|
|
if ( minBits >= escapeBits )
|
|
{
|
|
*bitstream = startBits; // reset bitstream state
|
|
doEscape = true;
|
|
printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits );
|
|
}
|
|
}
|
|
|
|
if ( doEscape == true )
|
|
{
|
|
// write bitstream header and coefs
|
|
BitBufferWrite( bitstream, 0, 12 );
|
|
BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 ); // LSB = 1 means "frame not compressed"
|
|
if ( partialFrame )
|
|
BitBufferWrite( bitstream, numSamples, 32 );
|
|
|
|
// just copy the input data to the output buffer
|
|
switch ( p->mBitDepth )
|
|
{
|
|
case 16:
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
BitBufferWrite( bitstream, inputBuffer[indx] >> 16, 16 );
|
|
break;
|
|
case 20:
|
|
// convert 20-bit data to 32-bit for simplicity
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
BitBufferWrite( bitstream, inputBuffer[indx] >> 12, 20 );
|
|
break;
|
|
case 24:
|
|
// convert 24-bit data to 32-bit for simplicity
|
|
for ( indx = 0, indx2 = 0; indx < numSamples; indx++, indx2 += stride )
|
|
{
|
|
p->mMixBufferU[indx] = inputBuffer[indx2] >> 8;
|
|
BitBufferWrite( bitstream, p->mMixBufferU[indx], 24 );
|
|
}
|
|
break;
|
|
case 32:
|
|
for ( indx = 0; indx < (numSamples * stride); indx += stride )
|
|
BitBufferWrite( bitstream, inputBuffer[indx], 32 );
|
|
break;
|
|
}
|
|
#if VERBOSE_DEBUG
|
|
DebugMsg( "escape!: %u vs %u\n", minBits, (numSamples * p->mBitDepth) );
|
|
#endif
|
|
}
|
|
|
|
Exit:
|
|
return status;
|
|
}
|
|
|
|
#if PRAGMA_MARK
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/*
|
|
Encode()
|
|
- encode the next block of samples
|
|
*/
|
|
int32_t
|
|
alac_encode(ALAC_ENCODER *p, uint32_t numChannels, uint32_t numSamples,
|
|
int32_t * theReadBuffer, unsigned char * theWriteBuffer, uint32_t * ioNumBytes)
|
|
{
|
|
uint32_t outputSize;
|
|
BitBuffer bitstream;
|
|
int32_t status;
|
|
|
|
// create a bit buffer structure pointing to our output buffer
|
|
BitBufferInit( &bitstream, theWriteBuffer, p->mMaxOutputBytes );
|
|
|
|
if ( numChannels == 2 )
|
|
{
|
|
// add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0
|
|
BitBufferWrite( &bitstream, ID_CPE, 3 );
|
|
BitBufferWrite( &bitstream, 0, 4 );
|
|
|
|
// encode stereo input buffer
|
|
if ( p->mFastMode == false )
|
|
status = EncodeStereo(p, &bitstream, theReadBuffer, 2, 0, numSamples );
|
|
else
|
|
status = EncodeStereoFast(p, &bitstream, theReadBuffer, 2, 0, numSamples );
|
|
RequireNoErr( status, goto Exit; );
|
|
}
|
|
else if ( numChannels == 1 )
|
|
{
|
|
// add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0
|
|
BitBufferWrite( &bitstream, ID_SCE, 3 );
|
|
BitBufferWrite( &bitstream, 0, 4 );
|
|
|
|
// encode mono input buffer
|
|
status = EncodeMono(p, &bitstream, theReadBuffer, 1, 0, numSamples );
|
|
RequireNoErr( status, goto Exit; );
|
|
}
|
|
else
|
|
{
|
|
int32_t * inputBuffer;
|
|
uint32_t tag;
|
|
uint32_t channelIndex;
|
|
uint32_t inputIncrement;
|
|
uint8_t stereoElementTag;
|
|
uint8_t monoElementTag;
|
|
uint8_t lfeElementTag;
|
|
|
|
inputBuffer = theReadBuffer;
|
|
inputIncrement = ((p->mBitDepth + 7) / 8);
|
|
|
|
stereoElementTag = 0;
|
|
monoElementTag = 0;
|
|
lfeElementTag = 0;
|
|
|
|
for ( channelIndex = 0; channelIndex < numChannels; )
|
|
{
|
|
tag = (sChannelMaps[numChannels - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3);
|
|
|
|
BitBufferWrite( &bitstream, tag, 3 );
|
|
switch ( tag )
|
|
{
|
|
case ID_SCE:
|
|
// mono
|
|
BitBufferWrite( &bitstream, monoElementTag, 4 );
|
|
|
|
status = EncodeMono(p, &bitstream, inputBuffer, numChannels, channelIndex, numSamples );
|
|
|
|
inputBuffer += inputIncrement;
|
|
channelIndex++;
|
|
monoElementTag++;
|
|
break;
|
|
|
|
case ID_CPE:
|
|
// stereo
|
|
BitBufferWrite( &bitstream, stereoElementTag, 4 );
|
|
|
|
status = EncodeStereo(p,&bitstream, inputBuffer, numChannels, channelIndex, numSamples );
|
|
|
|
inputBuffer += (inputIncrement * 2);
|
|
channelIndex += 2;
|
|
stereoElementTag++;
|
|
break;
|
|
|
|
case ID_LFE:
|
|
// LFE channel (subwoofer)
|
|
BitBufferWrite( &bitstream, lfeElementTag, 4 );
|
|
|
|
status = EncodeMono(p, &bitstream, inputBuffer, numChannels, channelIndex, numSamples );
|
|
|
|
inputBuffer += inputIncrement;
|
|
channelIndex++;
|
|
lfeElementTag++;
|
|
break;
|
|
|
|
default:
|
|
printf( "That ain't right! (%u)\n", tag );
|
|
status = kALAC_ParamError;
|
|
goto Exit;
|
|
}
|
|
|
|
RequireNoErr( status, goto Exit; );
|
|
}
|
|
}
|
|
|
|
#if VERBOSE_DEBUG
|
|
{
|
|
// if there is room left in the output buffer, add some random fill data to test decoder
|
|
int32_t bitsLeft;
|
|
int32_t bytesLeft;
|
|
|
|
bitsLeft = BitBufferGetPosition( &bitstream ) - 3; // - 3 for ID_END tag
|
|
bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8);
|
|
|
|
if ( (bytesLeft > 20) && ((bytesLeft & 0x4u) != 0) )
|
|
AddFiller( &bitstream, bytesLeft );
|
|
}
|
|
#endif
|
|
|
|
// add 3-bit frame end tag: ID_END
|
|
BitBufferWrite( &bitstream, ID_END, 3 );
|
|
|
|
// byte-align the output data
|
|
BitBufferByteAlign( &bitstream, true );
|
|
|
|
outputSize = BitBufferGetPosition( &bitstream ) / 8;
|
|
//Assert( outputSize <= mMaxOutputBytes );
|
|
|
|
|
|
// all good, let iTunes know what happened and remember the total number of input sample frames
|
|
*ioNumBytes = outputSize;
|
|
//mEncodedFrames += encodeMsg->numInputSamples;
|
|
|
|
// gather encoding stats
|
|
p->mTotalBytesGenerated += outputSize;
|
|
p->mMaxFrameBytes = MAX( p->mMaxFrameBytes, outputSize );
|
|
|
|
status = ALAC_noErr;
|
|
|
|
Exit:
|
|
return status;
|
|
}
|
|
|
|
|
|
#if PRAGMA_MARK
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/*
|
|
GetConfig()
|
|
*/
|
|
void
|
|
GetConfig(ALAC_ENCODER *p, ALACSpecificConfig * config )
|
|
{
|
|
config->frameLength = Swap32NtoB(p->mFrameSize);
|
|
config->compatibleVersion = (uint8_t) kALACCompatibleVersion;
|
|
config->bitDepth = (uint8_t) p->mBitDepth;
|
|
config->pb = (uint8_t) PB0;
|
|
config->kb = (uint8_t) KB0;
|
|
config->mb = (uint8_t) MB0;
|
|
config->numChannels = (uint8_t) p->mNumChannels;
|
|
config->maxRun = Swap16NtoB((uint16_t) MAX_RUN_DEFAULT);
|
|
config->maxFrameBytes = Swap32NtoB(p->mMaxFrameBytes);
|
|
config->avgBitRate = Swap32NtoB(p->mAvgBitRate);
|
|
config->sampleRate = Swap32NtoB(p->mOutputSampleRate);
|
|
}
|
|
|
|
uint32_t
|
|
alac_get_magic_cookie_size(uint32_t inNumChannels)
|
|
{
|
|
if (inNumChannels > 2)
|
|
{
|
|
return sizeof(ALACSpecificConfig) + kChannelAtomSize + sizeof(ALACAudioChannelLayout);
|
|
}
|
|
else
|
|
{
|
|
return sizeof(ALACSpecificConfig);
|
|
}
|
|
}
|
|
|
|
void
|
|
alac_get_magic_cookie(ALAC_ENCODER *p, void * outCookie, uint32_t * ioSize )
|
|
{
|
|
ALACSpecificConfig theConfig = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
ALACAudioChannelLayout theChannelLayout = {0, 0, 0};
|
|
uint8_t theChannelAtom[kChannelAtomSize] = {0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0};
|
|
uint32_t theCookieSize = sizeof(ALACSpecificConfig);
|
|
uint8_t * theCookiePointer = (uint8_t *)outCookie;
|
|
|
|
GetConfig(p, &theConfig);
|
|
if (theConfig.numChannels > 2)
|
|
{
|
|
theChannelLayout.mChannelLayoutTag = Swap32NtoB(ALACChannelLayoutTags[theConfig.numChannels - 1]);
|
|
theCookieSize += (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
|
|
}
|
|
if (*ioSize >= theCookieSize)
|
|
{
|
|
memcpy(theCookiePointer, &theConfig, sizeof(ALACSpecificConfig));
|
|
theChannelAtom[3] = (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
|
|
if (theConfig.numChannels > 2)
|
|
{
|
|
theCookiePointer += sizeof(ALACSpecificConfig);
|
|
memcpy(theCookiePointer, theChannelAtom, kChannelAtomSize);
|
|
theCookiePointer += kChannelAtomSize;
|
|
memcpy(theCookiePointer, &theChannelLayout, sizeof(ALACAudioChannelLayout));
|
|
}
|
|
*ioSize = theCookieSize;
|
|
}
|
|
else
|
|
{
|
|
*ioSize = 0; // no incomplete cookies
|
|
}
|
|
}
|
|
|
|
/*
|
|
alac_encoder_init()
|
|
- initialize the encoder component with the current config
|
|
*/
|
|
int32_t
|
|
alac_encoder_init (ALAC_ENCODER *p, uint32_t samplerate, uint32_t channels, uint32_t format_flags, uint32_t frameSize)
|
|
{
|
|
int32_t status;
|
|
uint32_t indx;
|
|
int32_t channel, search;
|
|
|
|
p->mFrameSize = (frameSize > 0 && frameSize <= ALAC_FRAME_LENGTH) ? frameSize : ALAC_FRAME_LENGTH ;
|
|
|
|
p->mOutputSampleRate = samplerate;
|
|
p->mNumChannels = channels;
|
|
switch (format_flags)
|
|
{
|
|
case 1:
|
|
p->mBitDepth = 16;
|
|
break;
|
|
case 2:
|
|
p->mBitDepth = 20;
|
|
break;
|
|
case 3:
|
|
p->mBitDepth = 24;
|
|
break;
|
|
case 4:
|
|
p->mBitDepth = 32;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// set up default encoding parameters and state
|
|
// - note: mFrameSize is set in the constructor or via alac_set_frame_size() which must be called before this routine
|
|
for ( indx = 0; indx < kALACMaxChannels; indx++ )
|
|
p->mLastMixRes[indx] = kDefaultMixRes;
|
|
|
|
// the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1)
|
|
// but note that this can be bigger than the input size!
|
|
// - since we don't yet know what our input format will be, use our max allowed sample size in the calculation
|
|
p->mMaxOutputBytes = p->mFrameSize * p->mNumChannels * ((10 + kMaxSampleSize) / 8) + 1;
|
|
|
|
status = ALAC_noErr;
|
|
|
|
// initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio
|
|
for ( channel = 0; channel < (int32_t) p->mNumChannels; channel++ )
|
|
{
|
|
for ( search = 0; search < kALACMaxSearches; search++ )
|
|
{
|
|
init_coefs( p->mCoefsU[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
|
|
init_coefs( p->mCoefsV[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
alac_get_source_format()
|
|
- given the input format, return one of our supported formats
|
|
*/
|
|
void
|
|
alac_get_source_format(ALAC_ENCODER *p, const AudioFormatDescription * source, AudioFormatDescription * output )
|
|
{
|
|
(void) output ;
|
|
// default is 16-bit native endian
|
|
// - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense
|
|
// to encode to 16-bit since the source was lossy in the first place
|
|
// - note: if not a supported bit depth, find the closest supported bit depth to the input one
|
|
if ( (source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) ||
|
|
( source->mBitsPerChannel <= 16 ) )
|
|
p->mBitDepth = 16;
|
|
else if ( source->mBitsPerChannel <= 20 )
|
|
p->mBitDepth = 20;
|
|
else if ( source->mBitsPerChannel <= 24 )
|
|
p->mBitDepth = 24;
|
|
else
|
|
p->mBitDepth = 32;
|
|
|
|
// we support 16/20/24/32-bit integer data at any sample rate and our target number of channels
|
|
// and sample rate were specified when we were configured
|
|
/*
|
|
MakeUncompressedAudioFormat( mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output );
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
#if VERBOSE_DEBUG
|
|
|
|
#if PRAGMA_MARK
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/*
|
|
AddFiller()
|
|
- add fill and data stream elements to the bitstream to test the decoder
|
|
*/
|
|
static void AddFiller( BitBuffer * bits, int32_t numBytes )
|
|
{
|
|
uint8_t tag;
|
|
int32_t indx;
|
|
|
|
// out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements
|
|
numBytes -= 6;
|
|
if ( numBytes <= 0 )
|
|
return;
|
|
|
|
// randomly pick Fill or Data Stream Element based on numBytes requested
|
|
tag = (numBytes & 0x8) ? ID_FIL : ID_DSE;
|
|
|
|
BitBufferWrite( bits, tag, 3 );
|
|
if ( tag == ID_FIL )
|
|
{
|
|
// can't write more than 269 bytes in a fill element
|
|
numBytes = (numBytes > 269) ? 269 : numBytes;
|
|
|
|
// fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size
|
|
if ( numBytes >= 15 )
|
|
{
|
|
uint16_t extensionSize;
|
|
|
|
BitBufferWrite( bits, 15, 4 );
|
|
|
|
// 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax
|
|
// - otherwise, there's no way to represent 15
|
|
// - for example, to really mean 15 bytes you must encode extensionSize = 1
|
|
// - why it's not like data stream elements I have no idea
|
|
extensionSize = (numBytes - 15) + 1;
|
|
//Assert( extensionSize <= 255 );
|
|
BitBufferWrite( bits, extensionSize, 8 );
|
|
}
|
|
else
|
|
BitBufferWrite( bits, numBytes, 4 );
|
|
|
|
BitBufferWrite( bits, 0x10, 8 ); // extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000
|
|
for ( indx = 0; indx < (numBytes - 1); indx++ )
|
|
BitBufferWrite( bits, 0xa5, 8 ); // fill_byte = b10100101 = 0xa5
|
|
}
|
|
else
|
|
{
|
|
// can't write more than 510 bytes in a data stream element
|
|
numBytes = (numBytes > 510) ? 510 : numBytes;
|
|
|
|
BitBufferWrite( bits, 0, 4 ); // element instance tag
|
|
BitBufferWrite( bits, 1, 1 ); // byte-align flag = true
|
|
|
|
// data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size
|
|
if ( numBytes >= 255 )
|
|
{
|
|
BitBufferWrite( bits, 255, 8 );
|
|
BitBufferWrite( bits, numBytes - 255, 8 );
|
|
}
|
|
else
|
|
BitBufferWrite( bits, numBytes, 8 );
|
|
|
|
BitBufferByteAlign( bits, true ); // byte-align with zeros
|
|
|
|
for ( indx = 0; indx < numBytes; indx++ )
|
|
BitBufferWrite( bits, 0x5a, 8 );
|
|
}
|
|
}
|
|
|
|
#endif /* VERBOSE_DEBUG */
|