1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | **********/ |
16 | // "liveMedia" |
17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
18 | // Filters for converting between raw PCM audio and uLaw |
19 | // Implementation |
20 | |
21 | #include "uLawAudioFilter.hh" |
22 | |
23 | ////////// 16-bit PCM (in various byte orders) -> 8-bit u-Law ////////// |
24 | |
25 | uLawFromPCMAudioSource* uLawFromPCMAudioSource |
26 | ::createNew(UsageEnvironment& env, FramedSource* inputSource, int byteOrdering) { |
27 | // "byteOrdering" must be 0, 1, or 2: |
28 | if (byteOrdering < 0 || byteOrdering > 2) { |
29 | env.setResultMsg("uLawFromPCMAudioSource::createNew(): bad \"byteOrdering\" parameter" ); |
30 | return NULL; |
31 | } |
32 | return new uLawFromPCMAudioSource(env, inputSource, byteOrdering); |
33 | } |
34 | |
35 | uLawFromPCMAudioSource |
36 | ::uLawFromPCMAudioSource(UsageEnvironment& env, FramedSource* inputSource, |
37 | int byteOrdering) |
38 | : FramedFilter(env, inputSource), |
39 | fByteOrdering(byteOrdering), fInputBuffer(NULL), fInputBufferSize(0) { |
40 | } |
41 | |
42 | uLawFromPCMAudioSource::~uLawFromPCMAudioSource() { |
43 | delete[] fInputBuffer; |
44 | } |
45 | |
46 | void uLawFromPCMAudioSource::doGetNextFrame() { |
47 | // Figure out how many bytes of input data to ask for, and increase |
48 | // our input buffer if necessary: |
49 | unsigned bytesToRead = fMaxSize*2; // because we're converting 16 bits->8 |
50 | if (bytesToRead > fInputBufferSize) { |
51 | delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead]; |
52 | fInputBufferSize = bytesToRead; |
53 | } |
54 | |
55 | // Arrange to read samples into the input buffer: |
56 | fInputSource->getNextFrame(fInputBuffer, bytesToRead, |
57 | afterGettingFrame, this, |
58 | FramedSource::handleClosure, this); |
59 | } |
60 | |
61 | void uLawFromPCMAudioSource |
62 | ::afterGettingFrame(void* clientData, unsigned frameSize, |
63 | unsigned numTruncatedBytes, |
64 | struct timeval presentationTime, |
65 | unsigned durationInMicroseconds) { |
66 | uLawFromPCMAudioSource* source = (uLawFromPCMAudioSource*)clientData; |
67 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
68 | presentationTime, durationInMicroseconds); |
69 | } |
70 | |
71 | #define BIAS 0x84 // the add-in bias for 16 bit samples |
72 | #define CLIP 32635 |
73 | |
74 | static unsigned char uLawFrom16BitLinear(u_int16_t sample) { |
75 | static int const exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, |
76 | 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, |
77 | 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, |
78 | 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, |
79 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, |
80 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, |
81 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, |
82 | 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, |
83 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
84 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
85 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
86 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
87 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
88 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
89 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, |
90 | 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; |
91 | unsigned char sign = (sample >> 8) & 0x80; |
92 | if (sign != 0) sample = -sample; // get the magnitude |
93 | |
94 | if (sample > CLIP) sample = CLIP; // clip the magnitude |
95 | sample += BIAS; |
96 | |
97 | unsigned char exponent = exp_lut[(sample>>7) & 0xFF]; |
98 | unsigned char mantissa = (sample >> (exponent+3)) & 0x0F; |
99 | unsigned char result = ~(sign | (exponent << 4) | mantissa); |
100 | if (result == 0 ) result = 0x02; // CCITT trap |
101 | |
102 | return result; |
103 | } |
104 | |
105 | void uLawFromPCMAudioSource |
106 | ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
107 | struct timeval presentationTime, |
108 | unsigned durationInMicroseconds) { |
109 | // Translate raw 16-bit PCM samples (in the input buffer) |
110 | // into uLaw samples (in the output buffer). |
111 | unsigned numSamples = frameSize/2; |
112 | switch (fByteOrdering) { |
113 | case 0: { // host order |
114 | u_int16_t* inputSample = (u_int16_t*)fInputBuffer; |
115 | for (unsigned i = 0; i < numSamples; ++i) { |
116 | fTo[i] = uLawFrom16BitLinear(inputSample[i]); |
117 | } |
118 | break; |
119 | } |
120 | case 1: { // little-endian order |
121 | for (unsigned i = 0; i < numSamples; ++i) { |
122 | u_int16_t const newValue = (fInputBuffer[2*i+1]<<8)|fInputBuffer[2*i]; |
123 | fTo[i] = uLawFrom16BitLinear(newValue); |
124 | } |
125 | break; |
126 | } |
127 | case 2: { // network (i.e., big-endian) order |
128 | for (unsigned i = 0; i < numSamples; ++i) { |
129 | u_int16_t const newValue = (fInputBuffer[2*i]<<8)|fInputBuffer[2*i+i]; |
130 | fTo[i] = uLawFrom16BitLinear(newValue); |
131 | } |
132 | break; |
133 | } |
134 | } |
135 | |
136 | // Complete delivery to the client: |
137 | fFrameSize = numSamples; |
138 | fNumTruncatedBytes = numTruncatedBytes; |
139 | fPresentationTime = presentationTime; |
140 | fDurationInMicroseconds = durationInMicroseconds; |
141 | afterGetting(this); |
142 | } |
143 | |
144 | |
145 | ////////// u-Law -> 16-bit PCM (in host order) ////////// |
146 | |
147 | PCMFromuLawAudioSource* PCMFromuLawAudioSource |
148 | ::createNew(UsageEnvironment& env, FramedSource* inputSource) { |
149 | return new PCMFromuLawAudioSource(env, inputSource); |
150 | } |
151 | |
152 | PCMFromuLawAudioSource |
153 | ::PCMFromuLawAudioSource(UsageEnvironment& env, |
154 | FramedSource* inputSource) |
155 | : FramedFilter(env, inputSource), |
156 | fInputBuffer(NULL), fInputBufferSize(0) { |
157 | } |
158 | |
159 | PCMFromuLawAudioSource::~PCMFromuLawAudioSource() { |
160 | delete[] fInputBuffer; |
161 | } |
162 | |
163 | void PCMFromuLawAudioSource::doGetNextFrame() { |
164 | // Figure out how many bytes of input data to ask for, and increase |
165 | // our input buffer if necessary: |
166 | unsigned bytesToRead = fMaxSize/2; // because we're converting 8 bits->16 |
167 | if (bytesToRead > fInputBufferSize) { |
168 | delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead]; |
169 | fInputBufferSize = bytesToRead; |
170 | } |
171 | |
172 | // Arrange to read samples into the input buffer: |
173 | fInputSource->getNextFrame(fInputBuffer, bytesToRead, |
174 | afterGettingFrame, this, |
175 | FramedSource::handleClosure, this); |
176 | } |
177 | |
178 | void PCMFromuLawAudioSource |
179 | ::afterGettingFrame(void* clientData, unsigned frameSize, |
180 | unsigned numTruncatedBytes, |
181 | struct timeval presentationTime, |
182 | unsigned durationInMicroseconds) { |
183 | PCMFromuLawAudioSource* source = (PCMFromuLawAudioSource*)clientData; |
184 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
185 | presentationTime, durationInMicroseconds); |
186 | } |
187 | |
188 | static u_int16_t linear16FromuLaw(unsigned char uLawByte) { |
189 | static int const exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; |
190 | uLawByte = ~uLawByte; |
191 | |
192 | Boolean sign = (uLawByte & 0x80) != 0; |
193 | unsigned char exponent = (uLawByte>>4) & 0x07; |
194 | unsigned char mantissa = uLawByte & 0x0F; |
195 | |
196 | u_int16_t result = exp_lut[exponent] + (mantissa << (exponent+3)); |
197 | if (sign) result = -result; |
198 | return result; |
199 | } |
200 | |
201 | void PCMFromuLawAudioSource |
202 | ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
203 | struct timeval presentationTime, |
204 | unsigned durationInMicroseconds) { |
205 | // Translate uLaw samples (in the input buffer) |
206 | // into 16-bit PCM samples (in the output buffer), in host order. |
207 | unsigned numSamples = frameSize; |
208 | u_int16_t* outputSample = (u_int16_t*)fTo; |
209 | for (unsigned i = 0; i < numSamples; ++i) { |
210 | outputSample[i] = linear16FromuLaw(fInputBuffer[i]); |
211 | } |
212 | |
213 | // Complete delivery to the client: |
214 | fFrameSize = numSamples*2; |
215 | fNumTruncatedBytes = numTruncatedBytes; |
216 | fPresentationTime = presentationTime; |
217 | fDurationInMicroseconds = durationInMicroseconds; |
218 | afterGetting(this); |
219 | } |
220 | |
221 | |
222 | ////////// 16-bit values (in host order) -> 16-bit network order ////////// |
223 | |
224 | NetworkFromHostOrder16* NetworkFromHostOrder16 |
225 | ::createNew(UsageEnvironment& env, FramedSource* inputSource) { |
226 | return new NetworkFromHostOrder16(env, inputSource); |
227 | } |
228 | |
229 | NetworkFromHostOrder16 |
230 | ::NetworkFromHostOrder16(UsageEnvironment& env, |
231 | FramedSource* inputSource) |
232 | : FramedFilter(env, inputSource) { |
233 | } |
234 | |
235 | NetworkFromHostOrder16::~NetworkFromHostOrder16() { |
236 | } |
237 | |
238 | void NetworkFromHostOrder16::doGetNextFrame() { |
239 | // Arrange to read data directly into the client's buffer: |
240 | fInputSource->getNextFrame(fTo, fMaxSize, |
241 | afterGettingFrame, this, |
242 | FramedSource::handleClosure, this); |
243 | } |
244 | |
245 | void NetworkFromHostOrder16 |
246 | ::afterGettingFrame(void* clientData, unsigned frameSize, |
247 | unsigned numTruncatedBytes, |
248 | struct timeval presentationTime, |
249 | unsigned durationInMicroseconds) { |
250 | NetworkFromHostOrder16* source = (NetworkFromHostOrder16*)clientData; |
251 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
252 | presentationTime, durationInMicroseconds); |
253 | } |
254 | |
255 | void NetworkFromHostOrder16 |
256 | ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
257 | struct timeval presentationTime, |
258 | unsigned durationInMicroseconds) { |
259 | // Translate the 16-bit values that we have just read from host |
260 | // to network order (in-place) |
261 | unsigned numValues = frameSize/2; |
262 | u_int16_t* value = (u_int16_t*)fTo; |
263 | for (unsigned i = 0; i < numValues; ++i) { |
264 | value[i] = htons(value[i]); |
265 | } |
266 | |
267 | // Complete delivery to the client: |
268 | fFrameSize = numValues*2; |
269 | fNumTruncatedBytes = numTruncatedBytes; |
270 | fPresentationTime = presentationTime; |
271 | fDurationInMicroseconds = durationInMicroseconds; |
272 | afterGetting(this); |
273 | } |
274 | |
275 | |
276 | ////////// 16-bit values (in network order) -> 16-bit host order ////////// |
277 | |
278 | HostFromNetworkOrder16* HostFromNetworkOrder16 |
279 | ::createNew(UsageEnvironment& env, FramedSource* inputSource) { |
280 | return new HostFromNetworkOrder16(env, inputSource); |
281 | } |
282 | |
283 | HostFromNetworkOrder16 |
284 | ::HostFromNetworkOrder16(UsageEnvironment& env, |
285 | FramedSource* inputSource) |
286 | : FramedFilter(env, inputSource) { |
287 | } |
288 | |
289 | HostFromNetworkOrder16::~HostFromNetworkOrder16() { |
290 | } |
291 | |
292 | void HostFromNetworkOrder16::doGetNextFrame() { |
293 | // Arrange to read data directly into the client's buffer: |
294 | fInputSource->getNextFrame(fTo, fMaxSize, |
295 | afterGettingFrame, this, |
296 | FramedSource::handleClosure, this); |
297 | } |
298 | |
299 | void HostFromNetworkOrder16 |
300 | ::afterGettingFrame(void* clientData, unsigned frameSize, |
301 | unsigned numTruncatedBytes, |
302 | struct timeval presentationTime, |
303 | unsigned durationInMicroseconds) { |
304 | HostFromNetworkOrder16* source = (HostFromNetworkOrder16*)clientData; |
305 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
306 | presentationTime, durationInMicroseconds); |
307 | } |
308 | |
309 | void HostFromNetworkOrder16 |
310 | ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
311 | struct timeval presentationTime, |
312 | unsigned durationInMicroseconds) { |
313 | // Translate the 16-bit values that we have just read from network |
314 | // to host order (in-place): |
315 | unsigned numValues = frameSize/2; |
316 | u_int16_t* value = (u_int16_t*)fTo; |
317 | for (unsigned i = 0; i < numValues; ++i) { |
318 | value[i] = ntohs(value[i]); |
319 | } |
320 | |
321 | // Complete delivery to the client: |
322 | fFrameSize = numValues*2; |
323 | fNumTruncatedBytes = numTruncatedBytes; |
324 | fPresentationTime = presentationTime; |
325 | fDurationInMicroseconds = durationInMicroseconds; |
326 | afterGetting(this); |
327 | } |
328 | |
329 | |
330 | ////////// 16-bit values: little-endian <-> big-endian ////////// |
331 | |
332 | EndianSwap16* |
333 | EndianSwap16::createNew(UsageEnvironment& env, FramedSource* inputSource) { |
334 | return new EndianSwap16(env, inputSource); |
335 | } |
336 | |
337 | EndianSwap16::EndianSwap16(UsageEnvironment& env, |
338 | FramedSource* inputSource) |
339 | : FramedFilter(env, inputSource) { |
340 | } |
341 | |
342 | EndianSwap16::~EndianSwap16() { |
343 | } |
344 | |
345 | void EndianSwap16::doGetNextFrame() { |
346 | // Arrange to read data directly into the client's buffer: |
347 | fInputSource->getNextFrame(fTo, fMaxSize, |
348 | afterGettingFrame, this, |
349 | FramedSource::handleClosure, this); |
350 | } |
351 | |
352 | void EndianSwap16::afterGettingFrame(void* clientData, unsigned frameSize, |
353 | unsigned numTruncatedBytes, |
354 | struct timeval presentationTime, |
355 | unsigned durationInMicroseconds) { |
356 | EndianSwap16* source = (EndianSwap16*)clientData; |
357 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
358 | presentationTime, durationInMicroseconds); |
359 | } |
360 | |
361 | void EndianSwap16::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
362 | struct timeval presentationTime, |
363 | unsigned durationInMicroseconds) { |
364 | // Swap the byte order of the 16-bit values that we have just read (in place): |
365 | unsigned numValues = frameSize/2; |
366 | u_int16_t* value = (u_int16_t*)fTo; |
367 | for (unsigned i = 0; i < numValues; ++i) { |
368 | u_int16_t const orig = value[i]; |
369 | value[i] = ((orig&0xFF)<<8) | ((orig&0xFF00)>>8); |
370 | } |
371 | |
372 | // Complete delivery to the client: |
373 | fFrameSize = numValues*2; |
374 | fNumTruncatedBytes = numTruncatedBytes + (frameSize - fFrameSize); |
375 | fPresentationTime = presentationTime; |
376 | fDurationInMicroseconds = durationInMicroseconds; |
377 | afterGetting(this); |
378 | } |
379 | |
380 | |
381 | ////////// 24-bit values: little-endian <-> big-endian ////////// |
382 | |
383 | EndianSwap24* |
384 | EndianSwap24::createNew(UsageEnvironment& env, FramedSource* inputSource) { |
385 | return new EndianSwap24(env, inputSource); |
386 | } |
387 | |
388 | EndianSwap24::EndianSwap24(UsageEnvironment& env, |
389 | FramedSource* inputSource) |
390 | : FramedFilter(env, inputSource) { |
391 | } |
392 | |
393 | EndianSwap24::~EndianSwap24() { |
394 | } |
395 | |
396 | void EndianSwap24::doGetNextFrame() { |
397 | // Arrange to read data directly into the client's buffer: |
398 | fInputSource->getNextFrame(fTo, fMaxSize, |
399 | afterGettingFrame, this, |
400 | FramedSource::handleClosure, this); |
401 | } |
402 | |
403 | void EndianSwap24::afterGettingFrame(void* clientData, unsigned frameSize, |
404 | unsigned numTruncatedBytes, |
405 | struct timeval presentationTime, |
406 | unsigned durationInMicroseconds) { |
407 | EndianSwap24* source = (EndianSwap24*)clientData; |
408 | source->afterGettingFrame1(frameSize, numTruncatedBytes, |
409 | presentationTime, durationInMicroseconds); |
410 | } |
411 | |
412 | void EndianSwap24::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, |
413 | struct timeval presentationTime, |
414 | unsigned durationInMicroseconds) { |
415 | // Swap the byte order of the 24-bit values that we have just read (in place): |
416 | unsigned const numValues = frameSize/3; |
417 | u_int8_t* p = fTo; |
418 | for (unsigned i = 0; i < numValues; ++i) { |
419 | u_int8_t tmp = p[0]; |
420 | p[0] = p[2]; |
421 | p[2] = tmp; |
422 | p += 3; |
423 | } |
424 | |
425 | // Complete delivery to the client: |
426 | fFrameSize = numValues*3; |
427 | fNumTruncatedBytes = numTruncatedBytes + (frameSize - fFrameSize); |
428 | fPresentationTime = presentationTime; |
429 | fDurationInMicroseconds = durationInMicroseconds; |
430 | afterGetting(this); |
431 | } |
432 | |