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