Changed ffmpeg log level to AV_LOG_QUIET
[platform/framework/native/media.git] / src / FMedia_AacEncoder.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 <FBaseInteger.h>
21 #include <FMediaTypes.h>
22 #include <FBaseSysLog.h>
23 #include "FMedia_Ffmpeg.h"
24 #include "FMedia_AacEncoder.h"
25
26 using namespace Tizen::Base;
27 using namespace Tizen::Io;
28 using namespace Tizen::Base::Collection;
29
30 namespace Tizen { namespace Media
31 {
32
33 _IAudioEncoder*
34 _AacEncoder_CreateInstance(void)
35 {
36         return new (std::nothrow) _AacEncoder();
37 }
38
39 _AacEncoder::_AacEncoder(void)
40 {
41         __pCodecCtx = null;
42         __pCodec = null;
43         __pResampleContext = null;
44         __pInputBuf = null;
45         __pInputFrame = null;
46 }
47
48 _AacEncoder::~_AacEncoder(void)
49 {
50         if (__pCodecCtx != null)
51         {
52                 avcodec_close(__pCodecCtx);
53                 av_free(__pCodecCtx);
54                 __pCodecCtx = null;
55                 __pCodec = null;
56         }
57
58         if (__pResampleContext != null)
59         {
60                 audio_resample_close(__pResampleContext);
61         }
62
63         if (__pInputBuf != null)
64         {
65                 delete[] __pInputBuf;
66         }
67
68         if (__pInputFrame != null)
69         {
70                 avcodec_free_frame(&__pInputFrame);
71         }
72
73 }
74
75 result
76 _AacEncoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
77 {
78         result r = E_SUCCESS;
79         int res = 0;
80         Integer* pKey = null;
81         Integer* pValue = null;
82         int key = -1;
83         int value = -1;
84         int inputSize = 0;
85
86         SysTryReturnResult(NID_MEDIA, __pCodecCtx == null, E_INVALID_STATE, "already constructed");
87
88         av_log_set_level (AV_LOG_QUIET);
89         avcodec_register_all();
90
91         __pCodec = avcodec_find_encoder(CODEC_ID_AAC);
92         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
93                            "[%s] Failed to get avcodec encoder", GetErrorMessage(E_SYSTEM));
94
95         __pCodecCtx = avcodec_alloc_context3(__pCodec);
96         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
97                            "[%s] Failed to allocate avcodec context", GetErrorMessage(E_SYSTEM));
98
99
100         __pCodecCtx->bit_rate = DEFAULT_BIT_RATE;
101         __pCodecCtx->sample_rate = DEFAULT_SAMPLE_RATE;
102         __pCodecCtx->channels = DEFAULT_CHANNEL_COUNT;
103         __pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLT;
104         __pCodecCtx->profile = FF_PROFILE_AAC_LOW;
105         __pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
106
107         if (pOption != null)
108         {
109                 // The initialization values are given in the Hashmap
110                 std::unique_ptr<IMapEnumerator> pMapEnum(pOption->GetMapEnumeratorN());
111                 if (pMapEnum.get() != null)
112                 {
113                         while (pMapEnum.get()->MoveNext() == E_SUCCESS)
114                         {
115                                 pKey = dynamic_cast<Integer*>(pMapEnum.get()->GetKey());
116                                 pValue = dynamic_cast<Integer*>(pMapEnum.get()->GetValue());
117
118                                 if (pKey == null || pValue == null)
119                                 {
120                                         continue;
121                                 }
122
123                                 key = pKey->ToInt();
124                                 value = pValue->ToInt();
125                                 switch (key)
126                                 {
127                                 case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
128                                         SysTryCatch(NID_MEDIA, (value == 0 || value == 1 || value == 2), r = E_OUT_OF_RANGE,
129                                                            E_OUT_OF_RANGE, "[%s] Audio Channel Type %d is outof range",GetErrorMessage(E_OUT_OF_RANGE));
130                                         __pCodecCtx->channels = value;
131                                         break;
132
133                                 case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
134                                         SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
135                                                            "[%s] Audio Sample rate is out of range", GetErrorMessage(E_OUT_OF_RANGE));
136                                         __pCodecCtx->sample_rate = value;
137                                         break;
138
139                                 case MEDIA_PROPERTY_AUDIO_BIT_RATE:
140                                         SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
141                                                            "[%s] Audio Bit Rate is out of range",GetErrorMessage(E_OUT_OF_RANGE));
142                                         __pCodecCtx->bit_rate = value;
143                                         break;
144
145                                 default:
146                                         SysLog(NID_MEDIA,"[%s] Ignore option:%d", GetErrorMessage(E_INVALID_ARG),key);
147                                         break;
148                                 }
149                         }
150
151                 }
152         }
153
154         if ( __pCodecCtx->bit_rate * SAMPLE_SIZE / __pCodecCtx->sample_rate
155                  > __pCodecCtx->channels * BYTES_PER_SAMPLE)
156         {
157                 __pCodecCtx->bit_rate = (__pCodecCtx->channels * BYTES_PER_SAMPLE)
158                         / SAMPLE_SIZE * __pCodecCtx->sample_rate;
159         }
160
161         res = avcodec_open2(__pCodecCtx, __pCodec, null);
162         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
163                            "[%s] avcodec open failed:%d", GetErrorMessage(E_SYSTEM), res);
164
165         if (__pCodecCtx->sample_fmt  == AV_SAMPLE_FMT_FLT)
166         {
167                 inputSize = __pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE;
168                 __pInputBuf = new (std::nothrow) byte[inputSize];
169                 SysTryCatch(NID_MEDIA, __pInputBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
170                            "[%s] Memory Allocation Failed", GetErrorMessage(E_OUT_OF_MEMORY));
171         }
172
173         __pInputFrame = avcodec_alloc_frame();
174         SysTryCatch(NID_MEDIA, __pInputFrame != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
175                            "[%s] Memory Allocation Failed", GetErrorMessage(E_OUT_OF_MEMORY));
176
177         __pInputFrame->nb_samples = __pCodecCtx->frame_size;
178         __pInputFrame->format = __pCodecCtx->sample_fmt;
179         __pInputFrame->channel_layout = __pCodecCtx->channel_layout;
180
181         return r;
182
183 CATCH:
184
185         if (__pCodecCtx != null)
186         {
187                 avcodec_close(__pCodecCtx);
188                 av_free(__pCodecCtx);
189                 __pCodecCtx = null;
190                 __pCodec = null;
191         }
192         return r;
193 }
194
195 result
196 _AacEncoder::Encode(const byte* srcBuf, int srcBufSize, int &srcBufUsed, byte* dstBuf, int dstBufSize, int &dstBufUsed)
197 {
198         result r = E_SUCCESS;
199         int res = 0;
200         int samples = 0;
201         int minSrcBufLength = 0;
202         int minDstBufLength = FF_MIN_BUFFER_SIZE;
203         int gotOutput = 0;
204         AVPacket outPacket;
205         outPacket.data = NULL;
206         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
207
208         minSrcBufLength = __pCodecCtx->frame_size * S16_SAMPLE_SIZE * __pCodecCtx->channels;
209
210         SysTryCatch(NID_MEDIA, srcBuf != null && dstBuf != null, r = E_INVALID_ARG, E_INVALID_ARG,
211                            "[%s] Invalid argument is used: 0x%x %d %d 0x%x %d %d",
212                            GetErrorMessage(E_INVALID_ARG), srcBuf, srcBufSize, minSrcBufLength, dstBuf, dstBufSize, minDstBufLength);
213
214         //Partial frame encoding is supported hence no need of checking sourcebuf length.
215         SysTryCatch(NID_MEDIA, dstBufSize >= minDstBufLength,
216                            r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
217                            "[%s] Destination Buffer Length is less than FF_MIN_BUFFER_SIZE: 0x%x %d %d 0x%x %d %d",
218                            GetErrorMessage(E_OUT_OF_MEMORY), srcBuf, srcBufSize, minSrcBufLength, dstBuf, dstBufSize, minDstBufLength);
219
220         //Only AV_SAMPLE_FMT_FLT is supported by FFMpeg AAC Encoder hence Sample Format Conversion from S16 to Float
221         if (__pCodecCtx->sample_fmt  == AV_SAMPLE_FMT_FLT)
222         {
223                 if (!__pResampleContext)
224                 {
225                         __pResampleContext = av_audio_resample_init(__pCodecCtx->channels, __pCodecCtx->channels,
226                                                 __pCodecCtx->sample_rate, __pCodecCtx->sample_rate,
227                                                 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16,
228                                                 0, 0, 0, 0);
229                         SysTryCatch(NID_MEDIA, __pResampleContext != null, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
230                                            "[%s] av audio resample init failed",GetErrorMessage(E_UNSUPPORTED_FORMAT));
231
232                 }
233
234                 memset(__pInputBuf,0,__pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE);
235
236                 if(srcBufSize >= minSrcBufLength)
237                 {
238                         samples = audio_resample (__pResampleContext, (short *) __pInputBuf, (short *)srcBuf, __pCodecCtx->frame_size);
239                 }
240                 else
241                 {
242                         int sampleCount = srcBufSize/(__pCodecCtx->channels * S16_SAMPLE_SIZE);
243                         samples = audio_resample (__pResampleContext, (short *) __pInputBuf, (short *)srcBuf,sampleCount);
244
245                 }
246
247                 res = avcodec_fill_audio_frame(__pInputFrame, __pCodecCtx->channels,__pCodecCtx->sample_fmt,
248                         (const uint8_t*)__pInputBuf,__pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE,0 );
249
250                 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
251                         "[%s] Fill Audio Frame failed %d", GetErrorMessage(E_SYSTEM));
252
253                 av_init_packet(&outPacket);
254                 outPacket.data = NULL;
255                 outPacket.size = 0;
256                 outPacket.priv = NULL;
257
258                 res = avcodec_encode_audio2(__pCodecCtx, &outPacket, __pInputFrame, &gotOutput);
259
260                 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
261                         "[%s] Audio Encode Failed %d", GetErrorMessage(E_SYSTEM));
262
263                 if(gotOutput)
264                 {
265                         memcpy(dstBuf,outPacket.data,outPacket.size);
266                         dstBufUsed = outPacket.size;
267                         av_free_packet(&outPacket);
268                 }
269                 else
270                 {
271                         dstBufUsed = 0;
272                 }
273         }
274
275         srcBufUsed = minSrcBufLength; //Input bytes used
276         return r;
277
278 CATCH:
279         if (__pResampleContext != null)
280         {
281                 audio_resample_close(__pResampleContext);
282         }
283
284         if(outPacket.data != null)
285         {
286                 av_free_packet(&outPacket);
287         }
288
289         return r;
290 }
291
292 result
293 _AacEncoder::Reset(void)
294 {
295         result r = E_SUCCESS;
296
297         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
298
299         avcodec_flush_buffers(__pCodecCtx);
300         return r;
301 }
302
303 }} // Tizen::Media