Tizen 2.0 Release
[framework/osp/media.git] / src / FMedia_Mp3Decoder.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 <stdio.h>
19 #include <FBaseColArrayListT.h>
20 #include <FBaseColHashMap.h>
21 #include <FMediaTypes.h>
22 #include <FMediaAudioTypes.h>
23 #include <FBaseSysLog.h>
24 #include "FMedia_Ffmpeg.h"
25 #include "FMedia_FfmpegUtil.h"
26 #include "FMedia_IAudioDecoder.h"
27 #include "FMedia_Mp3Decoder.h"
28
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 _IAudioDecoder*
37 _Mp3Decoder_CreateInstance(void)
38 {
39         return new (std::nothrow) _Mp3Decoder();
40 }
41
42 _Mp3Decoder::_Mp3Decoder(void)
43 {
44         __pCodecCtx = null;
45         __pCodec = null;
46         __decodeCalled = false;
47         __pOutBuf = null;
48 }
49
50 _Mp3Decoder::~_Mp3Decoder(void)
51 {
52         if (__pCodecCtx != null)
53         {
54                 avcodec_close(__pCodecCtx);
55                 av_free(__pCodecCtx);
56         }
57         if (__pOutBuf != null)
58         {
59                 delete[] __pOutBuf;
60         }
61 }
62
63 result
64 _Mp3Decoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
65 {
66         result r = E_SUCCESS;
67         int res = 0;
68
69         SysAssertf((__pCodecCtx == null && __pCodec == null), " Already Constructed .");\r
70
71         avcodec_register_all();
72
73         __pCodecCtx = avcodec_alloc_context();
74         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
75                             "[%s] AVCODEC Context Allcoation Failed",GetErrorMessage(E_SYSTEM));\r
76         __pCodec = avcodec_find_decoder(CODEC_ID_MP3);
77         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
78                            "[%s] AVCODEC Find Decoder Failed for CODEC_ID_MP3",GetErrorMessage(E_SYSTEM));\r
79 \r
80         res = avcodec_open(__pCodecCtx, __pCodec);
81         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
82                             "[%s] AVCODEC Codec Open Failed for CODEC_ID_MP3",GetErrorMessage(E_SYSTEM));\r
83
84         // AVCodecContext parameters
85         if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
86         {
87                 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
88         }
89
90         __pCodecCtx->debug_mv = 0; //set by user
91         __pCodecCtx->debug = 0; //set by user
92         __pCodecCtx->workaround_bugs = 1; //set by user
93         __pCodecCtx->lowres = 0; //set by user
94         __pCodecCtx->skip_frame = AVDISCARD_DEFAULT; //set by user
95         __pCodecCtx->skip_idct = AVDISCARD_DEFAULT; //set by user
96         __pCodecCtx->skip_loop_filter = AVDISCARD_DEFAULT; //set by user
97
98         __pOutBuf = new (std::nothrow) byte[_MIN_OUT_BUFFER_SIZE];
99         SysTryCatch(NID_MEDIA, __pOutBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
100                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
101
102         return r;
103
104 CATCH:
105         if (__pCodecCtx != null)
106         {
107                 avcodec_close(__pCodecCtx);
108                 av_free(__pCodecCtx);
109                 __pCodecCtx = null;
110                 __pCodec = null;
111         }
112         if (__pOutBuf != null)
113         {
114                 delete[] __pOutBuf;
115                 __pOutBuf = null;
116         }
117         return r;
118 }
119
120 result
121 _Mp3Decoder::Decode(const byte* pSrcBuf, int srcBufSize, int& srcBufUsed,
122                                         byte* pDstBuf, int dstBufSize, int& dstBufUsed)
123 {
124         result r = E_SUCCESS;
125         int res = 0;
126         AVPacket inputPacket;
127         int outBufSize = 0;
128         bool hasSyncBits = false;
129         byte* pOutBuf = null;
130         int srcBytesSkipped = 0;
131
132         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
133                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
134         SysTryCatch(NID_MEDIA, pSrcBuf != null && pDstBuf != null && srcBufSize > 0 && dstBufSize > 0,
135                            r = E_INVALID_ARG, E_INVALID_ARG,
136                           "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
137
138         av_init_packet(&inputPacket);
139
140         // check this routines is required
141         for (int i = 0; i < srcBufSize - 1; i++)
142         {
143                 if ((pSrcBuf[i] == 0xff) && ((pSrcBuf[i + 1] == 0xfb) || (pSrcBuf[i + 1] == 0xf3)))
144                 {
145                         hasSyncBits = true;
146                         inputPacket.size = srcBufSize - i;
147                         inputPacket.data = (uint8_t*)pSrcBuf + i;
148                         srcBytesSkipped = i;
149                         break;
150                 }
151         }
152
153         SysTryCatch(NID_MEDIA, hasSyncBits, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
154                            "[%s] The input data format is not supported ",GetErrorMessage(E_UNSUPPORTED_FORMAT));\r
155
156         if (dstBufSize >= _MIN_OUT_BUFFER_SIZE)
157         {
158                 pOutBuf = pDstBuf;
159                 outBufSize = dstBufSize;
160         }
161         else
162         {
163                 pOutBuf = __pOutBuf;
164                 outBufSize = _MIN_OUT_BUFFER_SIZE;
165         }
166
167         res = avcodec_decode_audio3(__pCodecCtx, (int16_t*)pOutBuf, &outBufSize, &inputPacket);
168         SysTryCatch(NID_MEDIA, (res > 0 && outBufSize > 0), r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
169                            "[%s] The input data format is not supported ",GetErrorMessage(E_UNSUPPORTED_FORMAT));\r
170
171         SysTryCatch(NID_MEDIA, dstBufSize >= outBufSize, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
172                           "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
173
174         dstBufUsed = outBufSize; // the decoded audio data size
175         srcBufUsed = res + srcBytesSkipped; // input bytes used
176         if (pOutBuf != pDstBuf)
177         {
178                 memcpy(pDstBuf, pOutBuf, outBufSize);
179                 __decodeCalled = true;
180         }
181         return r;
182
183 CATCH:
184         return r;
185 }
186
187 result
188 _Mp3Decoder::Probe(const byte* pSrcBuf, const int srcBufSize,
189                                    AudioSampleType& sampleType, AudioChannelType& channelType, int& sampleRate)
190 {
191         result r = E_SUCCESS;
192         int dstBufUsed = 0;
193         int srcBufUsed = 0;
194
195
196         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
197                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
198         SysTryCatch(NID_MEDIA, pSrcBuf != null && srcBufSize > 0, r = E_INVALID_ARG, E_INVALID_ARG,
199                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
200
201         r = Decode(pSrcBuf, srcBufSize, srcBufUsed, __pOutBuf, _MIN_OUT_BUFFER_SIZE, dstBufUsed);
202
203         SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r, "[%s] Decode failed", GetErrorMessage(r));
204
205         channelType = _FfmpegUtil::ToAudioChannelType(__pCodecCtx->channels);
206         sampleType = _FfmpegUtil::ToAudioSampleType(__pCodecCtx->sample_fmt);
207         sampleRate = __pCodecCtx->sample_rate;
208
209         SetLastResult(E_SUCCESS);
210         return r;
211
212 CATCH:
213         return r;
214 }
215
216 result
217 _Mp3Decoder::Reset(void)
218 {
219         result r = E_SUCCESS;
220
221         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
222                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
223
224         avcodec_flush_buffers(__pCodecCtx);
225
226         __decodeCalled = false;
227         SetLastResult(E_SUCCESS);
228         return r;
229
230 CATCH:
231         return r;
232 }
233
234 result
235 _Mp3Decoder::GetValue(MediaPropertyType type, int& value) const
236 {
237         result r = E_SUCCESS;
238
239         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
240                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
241         SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG,
242                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
243         SysTryCatch(NID_MEDIA, __decodeCalled, r = E_INVALID_STATE, E_INVALID_STATE,
244                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
245
246         switch (type)
247         {
248         case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
249                 value = _FfmpegUtil::ToAudioChannelType(__pCodecCtx->channels);
250         break;
251
252         case MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE:
253                 value = _FfmpegUtil::ToAudioSampleType(__pCodecCtx->sample_fmt);
254         break;
255
256         case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
257                 value = __pCodecCtx->sample_rate;
258         break;
259
260         case MEDIA_PROPERTY_AUDIO_BIT_RATE:
261                 value = __pCodecCtx->bit_rate;
262         break;
263
264         default:
265                 r = E_OBJ_NOT_FOUND;
266         break;
267         }
268         SetLastResult(r);
269         return r;
270
271 CATCH:
272         return r;
273 }
274
275 result
276 _Mp3Decoder::GetValue(MediaPropertyType type, float& value) const
277 {
278         result r = E_SUCCESS;
279         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
280                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
281         SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG,
282                           "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
283         SysTryCatch(NID_MEDIA, __decodeCalled, r = E_INVALID_STATE, E_INVALID_STATE,
284                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
285
286         return E_OBJ_NOT_FOUND;
287
288 CATCH:
289         return r;
290 }
291
292 Tizen::Base::Collection::IListT<MediaPropertyType>*
293 _Mp3Decoder::GetSupportedPropertyListN(void) const
294 {
295         result r = E_SUCCESS;
296         ArrayListT<MediaPropertyType>* pList = new (std::nothrow) ArrayListT<MediaPropertyType>;
297
298         SysTryCatch(NID_MEDIA, pList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
299                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
300         pList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_RATE);
301         pList->Add(MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE);
302         pList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE);
303         pList->Add(MEDIA_PROPERTY_AUDIO_BIT_RATE);
304         SetLastResult(r);
305         return pList;
306
307 CATCH:
308         return null;
309 }
310
311 bool
312 _Mp3Decoder::IsPropertySupported(MediaPropertyType type) const
313 {
314         result r = E_SUCCESS;
315
316         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_INVALID_STATE, E_INVALID_STATE,
317                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
318         SysTryCatch(NID_MEDIA, type == MEDIA_PROPERTY_AUDIO_SAMPLE_RATE ||
319                            type == MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE ||
320                            type == MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE ||
321                            type == MEDIA_PROPERTY_AUDIO_BIT_RATE,
322                            r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
323                           "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
324         SetLastResult(r);
325         return true;
326
327 CATCH:
328         return false;
329 }
330
331 } } // Tizen::Media