-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQBiLBCDecoder.mm
180 lines (143 loc) · 6.5 KB
/
QBiLBCDecoder.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "QBiLBCDecoder.h"
#import "QBAudioUtils.h"
/* Internal representation of an AAC-ELD decoder abstracting from the AudioConverter API */
typedef struct QBiLBCDecoder_ {
AudioStreamBasicDescription sourceFormat;
AudioStreamBasicDescription destinationFormat;
AudioConverterRef audioConverter;
UInt32 bytesToDecode;
void *decodeBuffer;
AudioStreamPacketDescription packetDesc[1];
Float64 samplingRate;
UInt32 frameSize;
UInt32 maxOutputPacketSize;
} QBiLBCDecoder;
QBiLBCDecoder* CreateiLBCDecoder()
{
/* Create and initialize a new decoder */
QBiLBCDecoder *decoder = (QBiLBCDecoder *) malloc(sizeof(QBiLBCDecoder));
memset(&(decoder->sourceFormat), 0, sizeof(AudioStreamBasicDescription));
memset(&(decoder->destinationFormat), 0, sizeof(AudioStreamBasicDescription));
decoder->bytesToDecode = 0;
decoder->decodeBuffer = NULL;
decoder->samplingRate = 0;
decoder->frameSize = 0;
decoder->maxOutputPacketSize = 0;
return decoder;
}
void DestroyiLBCDecoder(QBiLBCDecoder* decoder)
{
AudioConverterDispose(decoder->audioConverter);
free(decoder); /* free the allocated decoder memory */
}
int InitiLBCDecoder(QBiLBCDecoder* decoder, QBDecoderProperties props)
{
/* Copy the provided decoder properties */
decoder->samplingRate = props.samplingRate;
decoder->frameSize = props.frameSize;
/* We will decode to LPCM */
FillOutASBDForLPCM(decoder->destinationFormat,
decoder->samplingRate,
1,
8*sizeof(AudioSampleType),
8*sizeof(AudioSampleType),
false,
false);
/* from AAC-ELD, having the same sampling rate, but possibly a different channel configuration */
decoder->sourceFormat.mFormatID = kAudioFormatiLBC;
decoder->sourceFormat.mFramesPerPacket = 240;
decoder->sourceFormat.mBytesPerPacket = 50;
decoder->sourceFormat.mChannelsPerFrame = 1;
decoder->sourceFormat.mSampleRate = decoder->samplingRate;
/* Get the rest of the format info */
UInt32 dataSize = sizeof(decoder->sourceFormat);
QBCheckError(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&dataSize,
&(decoder->sourceFormat)), "QBiLBCDecoder AudioFormatGetProperty error");
/* Create a new AudioConverter instance for the conversion AAC-ELD -> LPCM */
QBCheckError(AudioConverterNew(&(decoder->sourceFormat),
&(decoder->destinationFormat),
&(decoder->audioConverter)), "QBiLBCDecoder AudioConverterNew error");
if (!decoder->audioConverter){
return -1;
}
/* Check for variable output packet size */
if (decoder->destinationFormat.mBytesPerPacket == 0){
UInt32 maxOutputSizePerPacket = 0;
dataSize = sizeof(maxOutputSizePerPacket);
AudioConverterGetProperty(decoder->audioConverter,
kAudioConverterPropertyMaximumOutputPacketSize,
&dataSize,
&maxOutputSizePerPacket);
decoder->maxOutputPacketSize = maxOutputSizePerPacket;
}else{
decoder->maxOutputPacketSize = decoder->destinationFormat.mBytesPerPacket;
}
return 0;
}
static OSStatus decodeProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData)
{
/* Get the current decoder state from the inUserData parameter */
QBiLBCDecoder *decoder = (QBiLBCDecoder *)inUserData;
/* Compute the maximum number of output packets */
UInt32 maxPackets = decoder->bytesToDecode / decoder->maxOutputPacketSize;
if (*ioNumberDataPackets > maxPackets){
/* If requested number of packets is bigger, adjust */
*ioNumberDataPackets = maxPackets;
}
/* If there is data to be decoded, set it accordingly */
if (decoder->bytesToDecode){
ioData->mBuffers[0].mData = decoder->decodeBuffer;
ioData->mBuffers[0].mDataByteSize = decoder->bytesToDecode;
ioData->mBuffers[0].mNumberChannels = 1;
}
/* And set the packet description */
if (outDataPacketDescription){
decoder->packetDesc[0].mStartOffset = 0;
decoder->packetDesc[0].mVariableFramesInPacket = 0;
decoder->packetDesc[0].mDataByteSize = decoder->bytesToDecode;
(*outDataPacketDescription) = decoder->packetDesc;
}
if (decoder->bytesToDecode == 0){
// We are currently out of data but want to keep on processing
// See Apple Technical Q&A QA1317
return 1;
}
decoder->bytesToDecode = 0;
return noErr;
}
int DecodeiLBC(QBiLBCDecoder* decoder, AudioBuffer *inData, AudioBuffer *outSamples)
{
OSStatus status = noErr;
/* Keep a reference to the samples that should be decoded */
decoder->decodeBuffer = inData->mData;
decoder->bytesToDecode = inData->mDataByteSize;
UInt32 outBufferMaxSizeBytes = decoder->frameSize * sizeof(AudioSampleType);
assert(outSamples->mDataByteSize <= outBufferMaxSizeBytes);
UInt32 numOutputDataPackets = outBufferMaxSizeBytes / decoder->maxOutputPacketSize;
/* Output packet stream are 512 LPCM samples */
AudioStreamPacketDescription outputPacketDesc[512];
/* Create the output buffer list */
AudioBufferList outBufferList;
outBufferList.mNumberBuffers = 1;
outBufferList.mBuffers[0].mNumberChannels = 1;
outBufferList.mBuffers[0].mDataByteSize = outSamples->mDataByteSize;
outBufferList.mBuffers[0].mData = outSamples->mData;
/* Start the decoding process */
status = AudioConverterFillComplexBuffer(decoder->audioConverter,
decodeProc,
decoder,
&numOutputDataPackets,
&outBufferList,
outputPacketDesc);
if (noErr != status){
return -1;
}
return 0;
}