xref: /aosp_15_r20/frameworks/av/media/libstagefright/codecs/g711/dec/SoftG711.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "SoftG711"
19 #include <utils/Log.h>
20 
21 #include "SoftG711.h"
22 
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/MediaDefs.h>
25 
26 #define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
27 
28 namespace android {
29 
30 template<class T>
InitOMXParams(T * params)31 static void InitOMXParams(T *params) {
32     params->nSize = sizeof(T);
33     params->nVersion.s.nVersionMajor = 1;
34     params->nVersion.s.nVersionMinor = 0;
35     params->nVersion.s.nRevision = 0;
36     params->nVersion.s.nStep = 0;
37 }
38 
SoftG711(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)39 SoftG711::SoftG711(
40         const char *name,
41         const OMX_CALLBACKTYPE *callbacks,
42         OMX_PTR appData,
43         OMX_COMPONENTTYPE **component)
44     : SimpleSoftOMXComponent(name, callbacks, appData, component),
45       mIsMLaw(true),
46       mSignalledError(false),
47       mNumChannels(1),
48       mSamplingRate(8000) {
49     if (!strcmp(name, "OMX.google.g711.alaw.decoder")) {
50         mIsMLaw = false;
51     } else {
52         CHECK(!strcmp(name, "OMX.google.g711.mlaw.decoder"));
53     }
54 
55     initPorts();
56 }
57 
~SoftG711()58 SoftG711::~SoftG711() {
59 }
60 
initPorts()61 void SoftG711::initPorts() {
62     OMX_PARAM_PORTDEFINITIONTYPE def;
63     InitOMXParams(&def);
64 
65     def.nPortIndex = 0;
66     def.eDir = OMX_DirInput;
67     def.nBufferCountMin = kNumBuffers;
68     def.nBufferCountActual = def.nBufferCountMin;
69     def.nBufferSize = 8192;
70     def.bEnabled = OMX_TRUE;
71     def.bPopulated = OMX_FALSE;
72     def.eDomain = OMX_PortDomainAudio;
73     def.bBuffersContiguous = OMX_FALSE;
74     def.nBufferAlignment = 1;
75 
76     def.format.audio.cMIMEType =
77         const_cast<char *>(
78                 mIsMLaw
79                     ? MEDIA_MIMETYPE_AUDIO_G711_MLAW
80                     : MEDIA_MIMETYPE_AUDIO_G711_ALAW);
81 
82     def.format.audio.pNativeRender = NULL;
83     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
84     def.format.audio.eEncoding = OMX_AUDIO_CodingG711;
85 
86     addPort(def);
87 
88     def.nPortIndex = 1;
89     def.eDir = OMX_DirOutput;
90     def.nBufferCountMin = kNumBuffers;
91     def.nBufferCountActual = def.nBufferCountMin;
92     def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t);
93     def.bEnabled = OMX_TRUE;
94     def.bPopulated = OMX_FALSE;
95     def.eDomain = OMX_PortDomainAudio;
96     def.bBuffersContiguous = OMX_FALSE;
97     def.nBufferAlignment = 2;
98 
99     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
100     def.format.audio.pNativeRender = NULL;
101     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
102     def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
103 
104     addPort(def);
105 }
106 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)107 OMX_ERRORTYPE SoftG711::internalGetParameter(
108         OMX_INDEXTYPE index, OMX_PTR params) {
109     switch (index) {
110         case OMX_IndexParamAudioPortFormat:
111         {
112             OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
113                 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
114 
115             if (!isValidOMXParam(formatParams)) {
116                 return OMX_ErrorBadParameter;
117             }
118 
119             if (formatParams->nPortIndex > 1) {
120                 return OMX_ErrorUndefined;
121             }
122 
123             if (formatParams->nIndex > 0) {
124                 return OMX_ErrorNoMore;
125             }
126 
127             formatParams->eEncoding =
128                 (formatParams->nPortIndex == 0)
129                     ? OMX_AUDIO_CodingG711 : OMX_AUDIO_CodingPCM;
130 
131             return OMX_ErrorNone;
132         }
133 
134         case OMX_IndexParamAudioPcm:
135         {
136             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
137                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
138 
139             if (!isValidOMXParam(pcmParams)) {
140                 return OMX_ErrorBadParameter;
141             }
142 
143             if (pcmParams->nPortIndex > 1) {
144                 return OMX_ErrorUndefined;
145             }
146 
147             pcmParams->eNumData = OMX_NumericalDataSigned;
148             pcmParams->eEndian = OMX_EndianBig;
149             pcmParams->bInterleaved = OMX_TRUE;
150             pcmParams->nBitPerSample = 16;
151             if (pcmParams->nPortIndex == 0) {
152                 // input port
153                 pcmParams->ePCMMode = mIsMLaw ? OMX_AUDIO_PCMModeMULaw
154                                               : OMX_AUDIO_PCMModeALaw;
155             } else {
156                 // output port
157                 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
158             }
159             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
160             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
161 
162             pcmParams->nChannels = mNumChannels;
163             pcmParams->nSamplingRate = mSamplingRate;
164 
165             return OMX_ErrorNone;
166         }
167 
168         default:
169             return SimpleSoftOMXComponent::internalGetParameter(index, params);
170     }
171 }
172 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)173 OMX_ERRORTYPE SoftG711::internalSetParameter(
174         OMX_INDEXTYPE index, const OMX_PTR params) {
175     switch (index) {
176         case OMX_IndexParamAudioPcm:
177         {
178             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
179                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
180 
181             if (!isValidOMXParam(pcmParams)) {
182                 return OMX_ErrorBadParameter;
183             }
184 
185             if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
186                 return OMX_ErrorUndefined;
187             }
188 
189             if (pcmParams->nChannels < 1 || pcmParams->nChannels > MAX_CHANNEL_COUNT) {
190                 return OMX_ErrorUndefined;
191             }
192 
193             if(pcmParams->nPortIndex == 0) {
194                 mNumChannels = pcmParams->nChannels;
195             }
196 
197             mSamplingRate = pcmParams->nSamplingRate;
198 
199             return OMX_ErrorNone;
200         }
201 
202         case OMX_IndexParamAudioPortFormat:
203         {
204             const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
205                 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
206 
207             if (!isValidOMXParam(formatParams)) {
208                 return OMX_ErrorBadParameter;
209             }
210 
211             if (formatParams->nPortIndex > 1) {
212                 return OMX_ErrorUndefined;
213             }
214 
215             if ((formatParams->nPortIndex == 0
216                         && formatParams->eEncoding != OMX_AUDIO_CodingG711)
217                 || (formatParams->nPortIndex == 1
218                         && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
219                 return OMX_ErrorUndefined;
220             }
221 
222             return OMX_ErrorNone;
223         }
224 
225         case OMX_IndexParamStandardComponentRole:
226         {
227             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
228                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
229 
230             if (!isValidOMXParam(roleParams)) {
231                 return OMX_ErrorBadParameter;
232             }
233 
234             if (mIsMLaw) {
235                 if (strncmp((const char *)roleParams->cRole,
236                             "audio_decoder.g711mlaw",
237                             OMX_MAX_STRINGNAME_SIZE - 1)) {
238                     return OMX_ErrorUndefined;
239                 }
240             } else {
241                 if (strncmp((const char *)roleParams->cRole,
242                             "audio_decoder.g711alaw",
243                             OMX_MAX_STRINGNAME_SIZE - 1)) {
244                     return OMX_ErrorUndefined;
245                 }
246             }
247 
248             return OMX_ErrorNone;
249         }
250 
251         default:
252             return SimpleSoftOMXComponent::internalSetParameter(index, params);
253     }
254 }
255 
onQueueFilled(OMX_U32)256 void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) {
257     if (mSignalledError) {
258         return;
259     }
260 
261     List<BufferInfo *> &inQueue = getPortQueue(0);
262     List<BufferInfo *> &outQueue = getPortQueue(1);
263 
264     while (!inQueue.empty() && !outQueue.empty()) {
265         BufferInfo *inInfo = *inQueue.begin();
266         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
267 
268         BufferInfo *outInfo = *outQueue.begin();
269         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
270 
271         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
272             inQueue.erase(inQueue.begin());
273             inInfo->mOwnedByUs = false;
274             notifyEmptyBufferDone(inHeader);
275 
276             outHeader->nFilledLen = 0;
277             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
278 
279             outQueue.erase(outQueue.begin());
280             outInfo->mOwnedByUs = false;
281             notifyFillBufferDone(outHeader);
282             return;
283         }
284 
285         if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
286             ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
287 
288             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
289             mSignalledError = true;
290         }
291 
292         if (inHeader->nFilledLen * sizeof(int16_t) > outHeader->nAllocLen) {
293             ALOGE("output buffer too small (%d).", outHeader->nAllocLen);
294             android_errorWriteLog(0x534e4554, "27793163");
295 
296             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
297             mSignalledError = true;
298             return;
299         }
300 
301         const uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
302 
303         if (mIsMLaw) {
304             DecodeMLaw(
305                     reinterpret_cast<int16_t *>(outHeader->pBuffer),
306                     inputptr, inHeader->nFilledLen);
307         } else {
308             DecodeALaw(
309                     reinterpret_cast<int16_t *>(outHeader->pBuffer),
310                     inputptr, inHeader->nFilledLen);
311         }
312 
313         outHeader->nTimeStamp = inHeader->nTimeStamp;
314         outHeader->nOffset = 0;
315         outHeader->nFilledLen = inHeader->nFilledLen * sizeof(int16_t);
316         outHeader->nFlags = 0;
317 
318         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
319             inHeader->nFilledLen = 0;
320         } else {
321             inInfo->mOwnedByUs = false;
322             inQueue.erase(inQueue.begin());
323             inInfo = NULL;
324             notifyEmptyBufferDone(inHeader);
325             inHeader = NULL;
326         }
327 
328         outInfo->mOwnedByUs = false;
329         outQueue.erase(outQueue.begin());
330         outInfo = NULL;
331         notifyFillBufferDone(outHeader);
332         outHeader = NULL;
333     }
334 }
335 
336 // static
DecodeALaw(int16_t * out,const uint8_t * in,size_t inSize)337 void SoftG711::DecodeALaw(
338         int16_t *out, const uint8_t *in, size_t inSize) {
339     while (inSize > 0) {
340         inSize--;
341         int32_t x = *in++;
342 
343         int32_t ix = x ^ 0x55;
344         ix &= 0x7f;
345 
346         int32_t iexp = ix >> 4;
347         int32_t mant = ix & 0x0f;
348 
349         if (iexp > 0) {
350             mant += 16;
351         }
352 
353         mant = (mant << 4) + 8;
354 
355         if (iexp > 1) {
356             mant = mant << (iexp - 1);
357         }
358 
359         *out++ = (x > 127) ? mant : -mant;
360     }
361 }
362 
363 // static
DecodeMLaw(int16_t * out,const uint8_t * in,size_t inSize)364 void SoftG711::DecodeMLaw(
365         int16_t *out, const uint8_t *in, size_t inSize) {
366     while (inSize > 0) {
367         inSize--;
368         int32_t x = *in++;
369 
370         int32_t mantissa = ~x;
371         int32_t exponent = (mantissa >> 4) & 7;
372         int32_t segment = exponent + 1;
373         mantissa &= 0x0f;
374 
375         int32_t step = 4 << segment;
376 
377         int32_t abs = (0x80L << exponent) + step * mantissa + step / 2 - 4 * 33;
378 
379         *out++ = (x < 0x80) ? -abs : abs;
380     }
381 }
382 
383 }  // namespace android
384 
385 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)386 android::SoftOMXComponent *createSoftOMXComponent(
387         const char *name, const OMX_CALLBACKTYPE *callbacks,
388         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
389     return new android::SoftG711(name, callbacks, appData, component);
390 }
391 
392