b1c3d03c92f087f2e22a43953187cf5e302cc335
[platform/framework/native/media.git] / src / FMedia_AacDecoder.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 #include <unique_ptr.h>
18 #include <FBaseColHashMap.h>
19 #include <FBaseColArrayListT.h>
20 #include <FMediaTypes.h>
21 #include <FMediaAudioTypes.h>
22 #include <FBaseSysLog.h>
23 #include <FBaseInteger.h>
24 #include "FMedia_Ffmpeg.h"
25 #include "FMedia_FfmpegUtil.h"
26 #include "FMedia_IAudioDecoder.h"
27 #include "FMedia_AacDecoder.h"
28 #include "FMedia_BitWriter.h"
29
30 using namespace std;
31 using namespace Tizen::Base;
32 using namespace Tizen::Io;
33 using namespace Tizen::Base::Collection;
34
35 namespace Tizen { namespace Media
36 {
37
38 #define ADTS_HEADER_SIZE 7
39
40 static const int _AAC_SAMPLE_RATE_INDEX[] = {
41         96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 };
42
43 _IAudioDecoder*
44 _AacDecoder_CreateInstance(void)
45 {
46         return new (std::nothrow) _AacDecoder();
47 }
48
49 _AacDecoder::_AacDecoder(void)
50 {
51         __pCodecCtx = null;
52         __pCodec = null;
53         __decodeCalled = false;
54         __pOutBuf = null;
55 }
56
57 _AacDecoder::~_AacDecoder(void)
58 {
59         if (__pCodecCtx != null)
60         {
61                 avcodec_close(__pCodecCtx);
62                 av_free(__pCodecCtx);
63                 __pCodecCtx = null;
64                 __pCodec = null;
65         }
66         if (__pOutBuf != null)
67         {
68                 delete[] __pOutBuf;
69         }
70 }
71
72 result
73 _AacDecoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
74 {
75         result r = E_SUCCESS;
76         int res = 0;
77         Integer* pKey = null;
78         Integer* pValue = null;
79         int key = -1;
80         int value = -1;
81
82         SysAssertf((__pCodecCtx == null && __pCodec == null), " Already Constructed .");
83
84         avcodec_register_all();
85
86         __pCodec = avcodec_find_decoder(CODEC_ID_AAC);
87         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
88                            "[%s] Find Decoder Failed for CODEC_ID_AAC",GetErrorMessage(E_SYSTEM));
89
90         __pCodecCtx = avcodec_alloc_context3(__pCodec);
91         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
92                            "[%s] Context Allcoation Failed",GetErrorMessage(E_SYSTEM));
93         if (pOption != null)
94         {
95                 // The initialization values are given in the Hashmap
96                 unique_ptr<IMapEnumerator> pMapEnum(pOption->GetMapEnumeratorN());
97                 if (pMapEnum.get() != null)
98                 {
99                         while (pMapEnum->MoveNext() == E_SUCCESS)
100                         {
101                                 pKey = static_cast<Integer*>(pMapEnum->GetKey());
102                                 pValue = static_cast<Integer*>(pMapEnum->GetValue());
103                                 if (pKey && pValue)
104                                 {
105                                         key = pKey->ToInt();
106                                         value = pValue->ToInt();
107                                         switch (key)
108                                         {
109                                         case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
110                                                 SysTryCatch(NID_MEDIA, (value == 0 || value == 1 || value == 2), r = E_OUT_OF_RANGE,
111                                                                    E_OUT_OF_RANGE, "[%s] Invalid argument is used. The value is out of range",GetErrorMessage(E_OUT_OF_RANGE));
112                                                 __pCodecCtx->channels = value;
113                                                 break;
114
115                                         case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
116                                                 SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
117                                                                    "[%s] Invalid argument: %d", GetErrorMessage(E_OUT_OF_RANGE), value);
118                                                 __pCodecCtx->sample_rate = value;
119                                                 break;
120
121                                         case MEDIA_PROPERTY_AUDIO_BIT_RATE:
122                                                 SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
123                                                                    "[%s] Invalid argument is used. The value is out of range",GetErrorMessage(E_OUT_OF_RANGE));
124                                                 __pCodecCtx->bit_rate = value;
125                                                 break;
126
127                                         default:
128                                                 break;
129                                         }
130                                 }
131                         } // while
132                 }
133         }
134
135         __pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
136         res = avcodec_open2(__pCodecCtx, __pCodec, null);
137         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
138                            "[%s] AVCODEC Codec Open Failed for CODEC_ID_AAC",GetErrorMessage(E_SYSTEM));
139
140         // AVCodecContext parameters
141         if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
142         {
143                 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
144         }
145
146         __pCodecCtx->debug_mv = 0; //set by user
147         __pCodecCtx->debug = 0; //set by user
148         __pCodecCtx->workaround_bugs = 1; //set by user
149         __pCodecCtx->extradata_size = 0;
150
151         __pOutBuf = new (std::nothrow) byte[DEFAULT_BUFFER_SIZE];
152         SysTryCatch(NID_MEDIA, __pOutBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
153                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));
154
155         return r;
156
157 CATCH:
158         if (__pCodecCtx != null)
159         {
160                 avcodec_close(__pCodecCtx);
161                 av_free(__pCodecCtx);
162                 __pCodecCtx = null;
163                 __pCodec = null;
164         }
165         return r;
166 }
167
168 ByteBuffer*
169 _AacDecoder::GetHeaderN(int sampleRate, int channels, int size, int pce_size)
170 {
171         result r = E_SUCCESS;
172         unique_ptr<ByteBuffer> pBuf(new (std::nothrow) ByteBuffer());
173
174         SysTryReturn(NID_MEDIA, pBuf.get() != null, null, E_OUT_OF_MEMORY, "new ByteBuffer() failed");
175
176         r = pBuf->Construct(ADTS_HEADER_SIZE);
177         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] ByteBuffer.Construct(%d) failed", GetErrorMessage(r), ADTS_HEADER_SIZE);
178
179         _BitWriter bw((byte*)pBuf->GetPointer(),pBuf->GetCapacity());
180         int sampleRateIndex = 0x0b;
181         int count = (int)(sizeof(_AAC_SAMPLE_RATE_INDEX)/sizeof(_AAC_SAMPLE_RATE_INDEX[0]));
182         for (int i = 0; i < count; i++)
183         {
184                 if (_AAC_SAMPLE_RATE_INDEX[i] == sampleRate)
185                 {
186                         sampleRateIndex = i;
187                         break;
188                 }
189         }
190
191         // fixed header
192         bw.PutBits(12, 0xfff);                  // syncword
193         bw.PutBits(1, 0);                               // id
194         bw.PutBits(2, 0);                               // layer
195         bw.PutBits(1, 1);                               // protection
196         bw.PutBits(2, 1);                               // profile : LC: 01
197         bw.PutBits(4, sampleRateIndex); // sample rate index
198         bw.PutBits(1, 0);                               // private
199         bw.PutBits(3, channels);                // channel
200         bw.PutBits(1, 0);                               // original copy
201         bw.PutBits(1, 0);                               // home
202
203         // variable header
204         bw.PutBits(1, 0);                               // copyright id bit
205         bw.PutBits(1, 0);                               // copyright id start
206         bw.PutBits(13, ADTS_HEADER_SIZE+size+pce_size);                         // aac frame length
207         bw.PutBits(11, 0x7ff);                  // buffer fullness
208         bw.PutBits(2, 0);                               // number of raw data blocks in frame
209
210         pBuf->SetPosition(0);
211         r = pBuf->SetLimit(ADTS_HEADER_SIZE);
212         SysTryReturn(NID_MEDIA, r == E_SUCCESS, null, r, "[%s] ByteBuffer.SetLimit(%d) failed", GetErrorMessage(r), ADTS_HEADER_SIZE);
213
214         return pBuf.release();
215 }
216
217 result
218 _AacDecoder::Decode(const byte* pSrcBuf, int srcBufSize, int& srcBufUsed,
219                                         byte* pDstBuf, int dstBufSize, int& dstBufUsed)
220 {
221         int res = 0;
222         AVPacket inputPacket;
223         int outBufSize = 0;
224         unique_ptr<AVFrame, _FfmpegDeleter> pOutFrame(avcodec_alloc_frame(), ffmpegDeleter);
225         int gotFrame = 0;
226
227         SysTryReturnResult(NID_MEDIA, __pCodecCtx != null, E_INVALID_STATE, "The instance is in invalid state");
228         SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && pDstBuf != null && srcBufSize > 0 && dstBufSize > 0),
229                            E_INVALID_ARG, "Invalid argument. pSrcBuf(0x%x), srcBufSize(%d), pDstBuf(0x%x), dstBufSize",
230                            pSrcBuf, srcBufSize, pDstBuf, dstBufSize);
231         SysTryReturnResult(NID_MEDIA, pOutFrame.get() != null, E_OUT_OF_MEMORY, "avcodec_alloc_frame() failed");
232
233         av_init_packet(&inputPacket);
234         inputPacket.size = srcBufSize;
235         inputPacket.data = (uint8_t*)pSrcBuf;
236
237         // Decoding the Audio  packet
238         res = avcodec_decode_audio4(__pCodecCtx, pOutFrame.get(), &gotFrame, &inputPacket);
239         // add adts header and try to decode
240         if ( res < 0 && !((pSrcBuf[0] == 0xff) && ((pSrcBuf[1] & 0xf6) == 0xf0)))
241         {
242                 unique_ptr<uint8_t[]> pInputData(new (std::nothrow) uint8_t[srcBufSize + ADTS_HEADER_SIZE]);
243                 unique_ptr<ByteBuffer> pAdtsHeader(GetHeaderN(__pCodecCtx->sample_rate,__pCodecCtx->channels, srcBufSize, 0));
244
245                 SysTryReturnResult(NID_MEDIA, pInputData.get() != null, E_OUT_OF_MEMORY, "new byte[%d] failed", srcBufSize + ADTS_HEADER_SIZE);
246                 SysTryReturnResult(NID_MEDIA, pAdtsHeader.get() != null, E_OUT_OF_MEMORY,
247                                 "ADTS header generate failed:%d %d %d", __pCodecCtx->sample_rate,__pCodecCtx->channels, srcBufSize);
248
249                 memcpy(pInputData.get(),pAdtsHeader->GetPointer(), ADTS_HEADER_SIZE);
250                 memcpy(pInputData.get() + ADTS_HEADER_SIZE, pSrcBuf, srcBufSize);
251                 inputPacket.size = srcBufSize + ADTS_HEADER_SIZE;
252                 inputPacket.data = pInputData.get();
253                 res = avcodec_decode_audio4(__pCodecCtx, pOutFrame.get(), &gotFrame, &inputPacket);
254         }
255
256         SysTryReturnResult(NID_MEDIA, (res > 0 && gotFrame > 0), E_UNSUPPORTED_FORMAT, "decode audio failed:%d", res);
257
258         if (inputPacket.size == (srcBufSize + ADTS_HEADER_SIZE))
259         {
260                 dstBufUsed = outBufSize; // The decoded audio data size
261                 srcBufUsed = res - ADTS_HEADER_SIZE; //Input bytes used, substract the appended header bytes
262         }
263         else
264         {
265                 dstBufUsed = outBufSize; // The decoded audio data size
266                 srcBufUsed = res; //Input bytes used            
267         }
268
269         outBufSize = av_samples_get_buffer_size(NULL, __pCodecCtx->channels, pOutFrame->nb_samples, __pCodecCtx->sample_fmt, 1);
270
271         SysTryReturnResult(NID_MEDIA, dstBufSize >= outBufSize, E_OUT_OF_MEMORY, "pDstBuf(%d) is smaller than decoded data(%d)", dstBufSize, outBufSize);
272
273         dstBufUsed = outBufSize; // The decoded audio data size
274         memcpy(pDstBuf, pOutFrame->data[0], outBufSize);
275
276         __decodeCalled = true;
277
278         return E_SUCCESS;
279 }
280
281 result
282 _AacDecoder::Probe(const byte* pSrcBuf, const int srcBufLength,
283                                                  Tizen::Media::AudioSampleType& sampleType,
284                                                  Tizen::Media::AudioChannelType& channelType, int& sampleRate)
285 {
286         result r = E_SUCCESS;
287         unique_ptr<byte[]> pDstBuf(new (std::nothrow) byte[DEFAULT_BUFFER_SIZE]);
288         int srcBufUsed = 0;
289         int dstBufUsed = 0;
290
291         SysTryReturnResult(NID_MEDIA, pDstBuf.get() != null, E_OUT_OF_MEMORY, "new byte[%d] failed", DEFAULT_BUFFER_SIZE);
292
293         r = Decode(pSrcBuf, srcBufLength, srcBufUsed, pDstBuf.get(), DEFAULT_BUFFER_SIZE, dstBufUsed);
294         SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Decode() failed", GetErrorMessage(r));
295
296         channelType = _FfmpegUtil::ToAudioChannelType(__pCodecCtx->channels);
297         sampleType = _FfmpegUtil::ToAudioSampleType(__pCodecCtx->sample_fmt);
298         sampleRate = __pCodecCtx->sample_rate;
299
300         SysTryReturnResult(NID_MEDIA, channelType != AUDIO_CHANNEL_TYPE_NONE, E_UNSUPPORTED_FORMAT, "Unknown channel type:%d", __pCodecCtx->channels);
301         SysTryReturnResult(NID_MEDIA, sampleType != AUDIO_TYPE_NONE, E_UNSUPPORTED_FORMAT, "Unknown sample type:%d", __pCodecCtx->sample_fmt);
302         SysTryReturnResult(NID_MEDIA, sampleRate > 0, E_UNSUPPORTED_FORMAT, "Unknown sample rate:%d", __pCodecCtx->sample_rate);
303
304         return E_SUCCESS;
305 }
306
307 result
308 _AacDecoder::Reset(void)
309 {
310         SysTryReturnResult(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), E_INVALID_STATE, "The instance is in invalid state");
311         avcodec_flush_buffers(__pCodecCtx);
312         __decodeCalled = false;
313
314         return E_SUCCESS;
315 }
316
317 result
318 _AacDecoder::GetValue(MediaPropertyType type, int& value) const
319 {
320         SysTryReturnResult(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), E_INVALID_STATE, "The instance is in invalid state");
321         SysTryReturnResult(NID_MEDIA, 0 < type, E_INVALID_ARG, "Invalid argument: type=%d", type);
322         SysTryReturnResult(NID_MEDIA, __decodeCalled, E_INVALID_STATE, "No decoding or probing has performed.");
323
324         switch (type)
325         {
326         case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
327                 value = _FfmpegUtil::ToAudioChannelType(__pCodecCtx->channels);
328                 break;
329
330         case MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE:
331                 value = _FfmpegUtil::ToAudioSampleType(__pCodecCtx->sample_fmt);
332                 break;
333
334         case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
335                 value = __pCodecCtx->sample_rate;
336                 break;
337
338         default:
339                 return E_OBJ_NOT_FOUND;
340                 break;
341         }
342
343         return E_SUCCESS;
344 }
345
346 result
347 _AacDecoder::GetValue(MediaPropertyType type, float& value) const
348 {
349         SysTryReturnResult(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), E_INVALID_STATE, "The instance is in invalid state");
350         SysTryReturnResult(NID_MEDIA, 0 < type, E_INVALID_ARG, "Invalid argument: type=%d", type);
351         SysTryReturnResult(NID_MEDIA, __decodeCalled, E_INVALID_STATE, "No decoding or probing has performed.");
352
353         return E_OBJ_NOT_FOUND;
354 }
355
356 Tizen::Base::Collection::IListT<MediaPropertyType>*
357 _AacDecoder::GetSupportedPropertyListN(void) const
358 {
359         result r = E_SUCCESS;
360         ArrayListT<MediaPropertyType>* pPropList = new  (std::nothrow) ArrayListT<MediaPropertyType>;
361
362         SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
363                           "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));
364         pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_RATE);
365         pPropList->Add(MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE);
366         pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE);
367         SetLastResult(r);
368         return pPropList;
369
370 CATCH:
371         return null;
372 }
373
374 bool
375 _AacDecoder::IsPropertySupported(MediaPropertyType type) const
376 {
377         result r = E_SUCCESS;
378         SysTryCatch(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), r = E_INVALID_STATE, E_INVALID_STATE,
379                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
380         SysTryCatch(NID_MEDIA, ( type == MEDIA_PROPERTY_AUDIO_SAMPLE_RATE || type == MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE ) ||
381                            (type == MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE ), r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
382                            "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));
383         SetLastResult(r);
384         return true;
385
386 CATCH:
387         return false;
388 }
389
390 }} // Tizen::Media