Changed ffmpeg log level to AV_LOG_QUIET
[platform/framework/native/media.git] / src / FMedia_AmrDecoder.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
18 #include <unique_ptr.h>
19 #include <FBaseColHashMap.h>
20 #include <FBaseColArrayListT.h>
21 #include <FBaseInteger.h>
22 #include <FMediaTypes.h>
23 #include <FMediaAudioTypes.h>
24 #include <FBaseSysLog.h>
25 #include <FMedia_Ffmpeg.h>
26 #include "FMedia_AmrDecoder.h"
27
28 using namespace std;
29 using namespace Tizen::Base;
30 using namespace Tizen::Io;
31 using namespace Tizen::Base::Collection;
32
33 namespace Tizen { namespace Media
34 {
35
36 static const byte _AMR_HEADER[] = { 0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A };
37
38 _IAudioDecoder*
39 _AmrDecoder_CreateInstance(void)
40 {
41         return new (std::nothrow) _AmrDecoder();
42 }
43
44 _AmrDecoder::_AmrDecoder(void)
45 {
46         __pCodecCtx = null;
47         __pCodec = null;
48         __pResampleContext = null;
49         __isHdrParsingDone = false;
50 }
51
52 _AmrDecoder::~_AmrDecoder(void)
53 {
54         if (__pCodecCtx != null)
55         {
56                 avcodec_close(__pCodecCtx);
57                 av_free(__pCodecCtx);
58                 __pCodecCtx = null;
59                 __pCodec = null;
60         }
61         if (__pResampleContext != null)
62         {
63                 audio_resample_close(__pResampleContext);
64         }
65 }
66
67
68 result
69 _AmrDecoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
70 {
71         result r = E_SUCCESS;
72         int res = 0;
73
74         SysAssertf((__pCodecCtx == null && __pCodec == null), " Already Constructed .");\r
75
76         av_log_set_level (AV_LOG_QUIET);
77         avcodec_register_all();
78
79         __pCodec = avcodec_find_decoder(CODEC_ID_AMR_NB);
80         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
81                            "[%s] AVCODEC Find Decoder Failed for CODEC_ID_AMR_NB ",GetErrorMessage(E_SYSTEM));
82
83         __pCodecCtx = avcodec_alloc_context3(__pCodec);
84         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
85                             "[%s] AVCODEC Context Allcoation Failed",GetErrorMessage(E_SYSTEM));\r
86 \r
87         __pCodecCtx->sample_rate = DEFAULT_SAMPLE_RATE;
88         __pCodecCtx->channels = 1; // AMR is always mono channel
89
90         res = avcodec_open2(__pCodecCtx, __pCodec, null);
91         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
92                            "[%s] AVCODEC Codec Open Failed for CODEC_ID_AMR_NB",GetErrorMessage(E_SYSTEM));\r
93
94         // AVCodecContext parameters
95         if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
96         {
97                 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
98         }
99
100         __pCodecCtx->debug_mv = 0; //set by user
101         __pCodecCtx->debug = 0; //set by user
102         __pCodecCtx->workaround_bugs = 1; //set by user
103         __pCodecCtx->lowres = 0; //set by user
104         __pCodecCtx->skip_frame = AVDISCARD_DEFAULT; //set by user
105         __pCodecCtx->skip_idct = AVDISCARD_DEFAULT; //set by user
106         __pCodecCtx->skip_loop_filter = AVDISCARD_DEFAULT; //set by user
107
108         return r;
109
110 CATCH:
111         if (__pCodecCtx != null)
112         {
113                 avcodec_close(__pCodecCtx);
114                 av_free(__pCodecCtx);
115                 __pCodecCtx = null;
116                 __pCodec = null;
117         }
118
119         return r;
120 }
121
122 result
123 _AmrDecoder::Decode(const byte* pSrcBuf, int srcBufSize, int &srcBufUsed,
124                                         byte* pDstBuf, int dstBufSize, int &dstBufUsed)
125 {
126         int res = 0;
127         AVPacket inputPacket;
128         int outBufSize = DECODED_FRAME_SIZE;
129         int samples = 0;
130         bool hasHdr = false;
131         unique_ptr<AVFrame, _FfmpegDeleter> pOutFrame(avcodec_alloc_frame(), ffmpegDeleter);
132         int gotFrame = 0;
133
134         SysTryReturnResult(NID_MEDIA, __pCodecCtx != null, E_INVALID_STATE, "The instance is in invalid state");\r
135         SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && pDstBuf != null && srcBufSize > 0 && dstBufSize >= 0 ), E_INVALID_ARG,
136                            "Invalid argument: pSrcBuf(0x%x), srcBufSize(%d), pDstBuf(0x%x), dstBufSize(%d)",
137                            pSrcBuf, srcBufSize, pDstBuf, dstBufSize);\r
138         SysTryReturnResult(NID_MEDIA, pOutFrame.get() != null, E_OUT_OF_MEMORY, "avcodec_alloc_frame() failed");
139
140         av_init_packet(&inputPacket);
141         inputPacket.size = srcBufSize;
142         inputPacket.data = (uint8_t*) pSrcBuf;
143
144         // Check whether the buffer passed has the amr header
145         if ( memcmp(pSrcBuf, _AMR_HEADER, sizeof(_AMR_HEADER)) == 0)
146         {
147                 // The input buffer has the header
148                 inputPacket.size = srcBufSize - NB_HEADER_SIZE;
149                 inputPacket.data = (uint8_t*)( pSrcBuf + NB_HEADER_SIZE);
150                 hasHdr = true;
151         }
152
153         // Decoding the Audio  packet
154         res = avcodec_decode_audio4(__pCodecCtx, pOutFrame.get(), &gotFrame, &inputPacket);
155
156         SysTryReturnResult(NID_MEDIA, res > 0, E_UNSUPPORTED_FORMAT, "decode audio failed:%d", res);
157
158         if (gotFrame)
159         {
160                 if (__pCodecCtx->sample_fmt != AV_SAMPLE_FMT_S16)
161                 {
162                         if (__pResampleContext == null)
163                         {
164                                 __pResampleContext = av_audio_resample_init(1 /* mono */, __pCodecCtx->channels,
165                                                 DEFAULT_SAMPLE_RATE, __pCodecCtx->sample_rate, AV_SAMPLE_FMT_S16, __pCodecCtx->sample_fmt, 0, 0, 0, 0);
166                                 SysTryReturnResult(NID_MEDIA, __pResampleContext != null, E_UNSUPPORTED_FORMAT, "resample init failed:ch(%d) sr(%d) fmt(%d)",
167                                                 __pCodecCtx->channels, __pCodecCtx->sample_rate, __pCodecCtx->sample_fmt);
168                         }
169
170                         outBufSize = av_samples_get_buffer_size(NULL, 1 /* mono */, pOutFrame->nb_samples, AV_SAMPLE_FMT_S16, 1);
171
172                         SysTryReturnResult(NID_MEDIA, dstBufSize >= outBufSize, E_OUT_OF_MEMORY, "pDstBuf(%d) is smaller than decoded data(%d)", dstBufSize, outBufSize);
173
174                         samples = audio_resample(__pResampleContext, (short *)pDstBuf, (short *)pOutFrame->data[0], pOutFrame->nb_samples);
175                         dstBufUsed = samples  * 2; // The decoded audio data size since each sample is 2 bytes
176                 }
177                 else
178                 {
179                         outBufSize = av_samples_get_buffer_size(NULL, __pCodecCtx->channels, pOutFrame->nb_samples, __pCodecCtx->sample_fmt, 1);
180
181                         SysTryReturnResult(NID_MEDIA, dstBufSize >= outBufSize, E_OUT_OF_MEMORY, "pDstBuf(%d) is smaller than decoded data(%d)", dstBufSize, outBufSize);
182
183                         memcpy(pDstBuf, pOutFrame->data[0], outBufSize);
184                         dstBufUsed = outBufSize; // The decoded audio data size
185                 }
186         }
187         else
188         {
189                 dstBufUsed = 0;
190         }
191
192         srcBufUsed = res;
193         if (hasHdr)
194         {
195                 srcBufUsed += NB_HEADER_SIZE;
196         }
197
198         return E_SUCCESS;
199 }
200
201 result
202 _AmrDecoder::Probe(const byte* pSrcBuf, const int srcBufLength,
203                                    Tizen::Media::AudioSampleType& sampleType,
204                                    Tizen::Media::AudioChannelType& channelType, int& sampleRate)
205 {
206         result r = E_SUCCESS;
207         unique_ptr<byte[]> pDstBuf(new (std::nothrow) byte[DECODED_FRAME_SIZE]);
208         int srcBufUsed = 0;
209         int dstBufUsed = 0;
210
211         SysTryReturnResult(NID_MEDIA, __pCodecCtx != null, E_INVALID_STATE, "The instance is in invalid state");\r
212         SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && srcBufLength > 0), E_INVALID_ARG,
213                            "Invalid argument: pSrcBuf(0x%x) srcBufLength(%d)", pSrcBuf, srcBufLength);\r
214         SysTryReturnResult(NID_MEDIA, pDstBuf.get() != null, E_OUT_OF_MEMORY, "new byte[%d] failed", DECODED_FRAME_SIZE);
215
216         r = Decode(pSrcBuf, srcBufLength, srcBufUsed, pDstBuf.get(), DECODED_FRAME_SIZE, dstBufUsed);
217
218         SysTryReturn(NID_MEDIA, r == E_SUCCESS, r, r, "[%s] Decode failed", GetErrorMessage(r));
219
220         channelType = AUDIO_CHANNEL_TYPE_MONO;
221         sampleType = AUDIO_TYPE_PCM_S16_LE;
222         sampleRate = DEFAULT_SAMPLE_RATE;
223
224         return r;
225 }
226
227 result
228 _AmrDecoder::Reset(void)
229 {
230         result r = E_SUCCESS;
231
232         SysTryCatch(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), r = E_INVALID_STATE, E_INVALID_STATE,
233                            "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
234         avcodec_flush_buffers(__pCodecCtx);
235         __isHdrParsingDone = false;
236         return r;
237
238 CATCH:
239         return r;
240 }
241
242 result
243 _AmrDecoder::GetValue(MediaPropertyType type, int& value) const
244 {
245         result r = E_SUCCESS;
246
247         SysTryCatch(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), r = E_INVALID_STATE, E_INVALID_STATE,
248                            "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
249         SysTryCatch(NID_MEDIA, 0 < type, r = E_INVALID_ARG, E_INVALID_ARG,
250                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
251         SysTryCatch(NID_MEDIA, __pCodecCtx->sample_rate != 0, r = E_INVALID_STATE, E_INVALID_STATE,
252                            "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
253
254         switch (type)
255         {
256         case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
257                 value = AUDIO_CHANNEL_TYPE_MONO;
258         break;
259
260         case MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE:
261                 value = AUDIO_TYPE_PCM_S16_LE;
262         break;
263
264         case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
265                 value = DEFAULT_SAMPLE_RATE;
266         break;
267
268         default:
269                 return E_OBJ_NOT_FOUND;
270         break;
271         }
272         return r;
273
274 CATCH:
275         return r;
276 }
277
278 result
279 _AmrDecoder::GetValue(MediaPropertyType type, float& value) const
280 {
281         result r = E_SUCCESS;
282
283         SysTryCatch(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), r = E_INVALID_STATE, E_INVALID_STATE,
284                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
285         SysTryCatch(NID_MEDIA, 0 < type, r = E_INVALID_ARG, E_INVALID_ARG,
286                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
287         SysTryCatch(NID_MEDIA, type < MEDIA_PROPERTY_VIDEO_WIDTH || type >= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
288                            r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
289         SysTryCatch(NID_MEDIA, __pCodecCtx->sample_rate != 0, r = E_INVALID_STATE, E_INVALID_STATE,
290                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
291
292         return E_OBJ_NOT_FOUND;
293
294 CATCH:
295         return r;
296 }
297
298 Tizen::Base::Collection::IListT<MediaPropertyType>*
299 _AmrDecoder::GetSupportedPropertyListN(void) const
300 {
301         result r = E_SUCCESS;
302         ArrayListT<MediaPropertyType>* pPropList = new  (std::nothrow) ArrayListT<MediaPropertyType>;
303
304         SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
305                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
306         pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_RATE);
307         pPropList->Add(MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE);
308         pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE);
309         SetLastResult(r);
310         return pPropList;
311
312 CATCH:
313         return null;
314 }
315
316 bool
317 _AmrDecoder::IsPropertySupported(MediaPropertyType type) const
318 {
319         result r = E_SUCCESS;
320
321         SysTryCatch(NID_MEDIA, (__pCodecCtx != null && __pCodec != null), r = E_INVALID_STATE, E_INVALID_STATE,
322                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
323         SysTryCatch(NID_MEDIA, (type == MEDIA_PROPERTY_AUDIO_SAMPLE_RATE || type == MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE ) ||
324                            (type == MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE  ), r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
325                            "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
326         SetLastResult(r);
327         return true;
328
329 CATCH:
330         return false;
331 }
332
333 };
334 };