blob: 1954b47965361370028c5f712faae1719fd90e1b [file] [log] [blame]
/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********/
// "liveMedia"
// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
// Filters for converting between raw PCM audio and uLaw
// Implementation
#include "uLawAudioFilter.hh"
////////// 16-bit PCM (in various byte orders) -> 8-bit u-Law //////////
uLawFromPCMAudioSource* uLawFromPCMAudioSource
::createNew(UsageEnvironment& env, FramedSource* inputSource, int byteOrdering) {
// "byteOrdering" must be 0, 1, or 2:
if (byteOrdering < 0 || byteOrdering > 2) {
env.setResultMsg("uLawFromPCMAudioSource::createNew(): bad \"byteOrdering\" parameter");
return NULL;
}
return new uLawFromPCMAudioSource(env, inputSource, byteOrdering);
}
uLawFromPCMAudioSource
::uLawFromPCMAudioSource(UsageEnvironment& env, FramedSource* inputSource,
int byteOrdering)
: FramedFilter(env, inputSource),
fByteOrdering(byteOrdering), fInputBuffer(NULL), fInputBufferSize(0) {
}
uLawFromPCMAudioSource::~uLawFromPCMAudioSource() {
delete[] fInputBuffer;
}
void uLawFromPCMAudioSource::doGetNextFrame() {
// Figure out how many bytes of input data to ask for, and increase
// our input buffer if necessary:
unsigned bytesToRead = fMaxSize*2; // because we're converting 16 bits->8
if (bytesToRead > fInputBufferSize) {
delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead];
fInputBufferSize = bytesToRead;
}
// Arrange to read samples into the input buffer:
fInputSource->getNextFrame(fInputBuffer, bytesToRead,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void uLawFromPCMAudioSource
::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
uLawFromPCMAudioSource* source = (uLawFromPCMAudioSource*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
#define BIAS 0x84 // the add-in bias for 16 bit samples
#define CLIP 32635
static unsigned char uLawFrom16BitLinear(u_int16_t sample) {
static int const exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
unsigned char sign = (sample >> 8) & 0x80;
if (sign != 0) sample = -sample; // get the magnitude
if (sample > CLIP) sample = CLIP; // clip the magnitude
sample += BIAS;
unsigned char exponent = exp_lut[(sample>>7) & 0xFF];
unsigned char mantissa = (sample >> (exponent+3)) & 0x0F;
unsigned char result = ~(sign | (exponent << 4) | mantissa);
if (result == 0 ) result = 0x02; // CCITT trap
return result;
}
void uLawFromPCMAudioSource
::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Translate raw 16-bit PCM samples (in the input buffer)
// into uLaw samples (in the output buffer).
unsigned numSamples = frameSize/2;
switch (fByteOrdering) {
case 0: { // host order
u_int16_t* inputSample = (u_int16_t*)fInputBuffer;
for (unsigned i = 0; i < numSamples; ++i) {
fTo[i] = uLawFrom16BitLinear(inputSample[i]);
}
break;
}
case 1: { // little-endian order
for (unsigned i = 0; i < numSamples; ++i) {
u_int16_t const newValue = (fInputBuffer[2*i+1]<<8)|fInputBuffer[2*i];
fTo[i] = uLawFrom16BitLinear(newValue);
}
break;
}
case 2: { // network (i.e., big-endian) order
for (unsigned i = 0; i < numSamples; ++i) {
u_int16_t const newValue = (fInputBuffer[2*i]<<8)|fInputBuffer[2*i+i];
fTo[i] = uLawFrom16BitLinear(newValue);
}
break;
}
}
// Complete delivery to the client:
fFrameSize = numSamples;
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
////////// u-Law -> 16-bit PCM (in host order) //////////
PCMFromuLawAudioSource* PCMFromuLawAudioSource
::createNew(UsageEnvironment& env, FramedSource* inputSource) {
return new PCMFromuLawAudioSource(env, inputSource);
}
PCMFromuLawAudioSource
::PCMFromuLawAudioSource(UsageEnvironment& env,
FramedSource* inputSource)
: FramedFilter(env, inputSource),
fInputBuffer(NULL), fInputBufferSize(0) {
}
PCMFromuLawAudioSource::~PCMFromuLawAudioSource() {
delete[] fInputBuffer;
}
void PCMFromuLawAudioSource::doGetNextFrame() {
// Figure out how many bytes of input data to ask for, and increase
// our input buffer if necessary:
unsigned bytesToRead = fMaxSize/2; // because we're converting 8 bits->16
if (bytesToRead > fInputBufferSize) {
delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead];
fInputBufferSize = bytesToRead;
}
// Arrange to read samples into the input buffer:
fInputSource->getNextFrame(fInputBuffer, bytesToRead,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void PCMFromuLawAudioSource
::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
PCMFromuLawAudioSource* source = (PCMFromuLawAudioSource*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
static u_int16_t linear16FromuLaw(unsigned char uLawByte) {
static int const exp_lut[8] = {0,132,396,924,1980,4092,8316,16764};
uLawByte = ~uLawByte;
Boolean sign = (uLawByte & 0x80) != 0;
unsigned char exponent = (uLawByte>>4) & 0x07;
unsigned char mantissa = uLawByte & 0x0F;
u_int16_t result = exp_lut[exponent] + (mantissa << (exponent+3));
if (sign) result = -result;
return result;
}
void PCMFromuLawAudioSource
::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Translate uLaw samples (in the input buffer)
// into 16-bit PCM samples (in the output buffer), in host order.
unsigned numSamples = frameSize;
u_int16_t* outputSample = (u_int16_t*)fTo;
for (unsigned i = 0; i < numSamples; ++i) {
outputSample[i] = linear16FromuLaw(fInputBuffer[i]);
}
// Complete delivery to the client:
fFrameSize = numSamples*2;
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
////////// 16-bit values (in host order) -> 16-bit network order //////////
NetworkFromHostOrder16* NetworkFromHostOrder16
::createNew(UsageEnvironment& env, FramedSource* inputSource) {
return new NetworkFromHostOrder16(env, inputSource);
}
NetworkFromHostOrder16
::NetworkFromHostOrder16(UsageEnvironment& env,
FramedSource* inputSource)
: FramedFilter(env, inputSource) {
}
NetworkFromHostOrder16::~NetworkFromHostOrder16() {
}
void NetworkFromHostOrder16::doGetNextFrame() {
// Arrange to read data directly into the client's buffer:
fInputSource->getNextFrame(fTo, fMaxSize,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void NetworkFromHostOrder16
::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
NetworkFromHostOrder16* source = (NetworkFromHostOrder16*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
void NetworkFromHostOrder16
::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Translate the 16-bit values that we have just read from host
// to network order (in-place)
unsigned numValues = frameSize/2;
u_int16_t* value = (u_int16_t*)fTo;
for (unsigned i = 0; i < numValues; ++i) {
value[i] = htons(value[i]);
}
// Complete delivery to the client:
fFrameSize = numValues*2;
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
////////// 16-bit values (in network order) -> 16-bit host order //////////
HostFromNetworkOrder16* HostFromNetworkOrder16
::createNew(UsageEnvironment& env, FramedSource* inputSource) {
return new HostFromNetworkOrder16(env, inputSource);
}
HostFromNetworkOrder16
::HostFromNetworkOrder16(UsageEnvironment& env,
FramedSource* inputSource)
: FramedFilter(env, inputSource) {
}
HostFromNetworkOrder16::~HostFromNetworkOrder16() {
}
void HostFromNetworkOrder16::doGetNextFrame() {
// Arrange to read data directly into the client's buffer:
fInputSource->getNextFrame(fTo, fMaxSize,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void HostFromNetworkOrder16
::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
HostFromNetworkOrder16* source = (HostFromNetworkOrder16*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
void HostFromNetworkOrder16
::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Translate the 16-bit values that we have just read from network
// to host order (in-place):
unsigned numValues = frameSize/2;
u_int16_t* value = (u_int16_t*)fTo;
for (unsigned i = 0; i < numValues; ++i) {
value[i] = ntohs(value[i]);
}
// Complete delivery to the client:
fFrameSize = numValues*2;
fNumTruncatedBytes = numTruncatedBytes;
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
////////// 16-bit values: little-endian <-> big-endian //////////
EndianSwap16*
EndianSwap16::createNew(UsageEnvironment& env, FramedSource* inputSource) {
return new EndianSwap16(env, inputSource);
}
EndianSwap16::EndianSwap16(UsageEnvironment& env,
FramedSource* inputSource)
: FramedFilter(env, inputSource) {
}
EndianSwap16::~EndianSwap16() {
}
void EndianSwap16::doGetNextFrame() {
// Arrange to read data directly into the client's buffer:
fInputSource->getNextFrame(fTo, fMaxSize,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void EndianSwap16::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
EndianSwap16* source = (EndianSwap16*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
void EndianSwap16::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Swap the byte order of the 16-bit values that we have just read (in place):
unsigned numValues = frameSize/2;
u_int16_t* value = (u_int16_t*)fTo;
for (unsigned i = 0; i < numValues; ++i) {
u_int16_t const orig = value[i];
value[i] = ((orig&0xFF)<<8) | ((orig&0xFF00)>>8);
}
// Complete delivery to the client:
fFrameSize = numValues*2;
fNumTruncatedBytes = numTruncatedBytes + (frameSize - fFrameSize);
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}
////////// 24-bit values: little-endian <-> big-endian //////////
EndianSwap24*
EndianSwap24::createNew(UsageEnvironment& env, FramedSource* inputSource) {
return new EndianSwap24(env, inputSource);
}
EndianSwap24::EndianSwap24(UsageEnvironment& env,
FramedSource* inputSource)
: FramedFilter(env, inputSource) {
}
EndianSwap24::~EndianSwap24() {
}
void EndianSwap24::doGetNextFrame() {
// Arrange to read data directly into the client's buffer:
fInputSource->getNextFrame(fTo, fMaxSize,
afterGettingFrame, this,
FramedSource::handleClosure, this);
}
void EndianSwap24::afterGettingFrame(void* clientData, unsigned frameSize,
unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
EndianSwap24* source = (EndianSwap24*)clientData;
source->afterGettingFrame1(frameSize, numTruncatedBytes,
presentationTime, durationInMicroseconds);
}
void EndianSwap24::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime,
unsigned durationInMicroseconds) {
// Swap the byte order of the 24-bit values that we have just read (in place):
unsigned const numValues = frameSize/3;
u_int8_t* p = fTo;
for (unsigned i = 0; i < numValues; ++i) {
u_int8_t tmp = p[0];
p[0] = p[2];
p[2] = tmp;
p += 3;
}
// Complete delivery to the client:
fFrameSize = numValues*3;
fNumTruncatedBytes = numTruncatedBytes + (frameSize - fFrameSize);
fPresentationTime = presentationTime;
fDurationInMicroseconds = durationInMicroseconds;
afterGetting(this);
}