Tizen 2.0 Release
[framework/osp/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         avcodec_register_all();
89
90         __pCodec = avcodec_find_encoder(CODEC_ID_AAC);
91         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
92                            "[%s] Failed to get avcodec encoder", GetErrorMessage(E_SYSTEM));
93
94         __pCodecCtx = avcodec_alloc_context3(__pCodec);
95         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
96                            "[%s] Failed to allocate avcodec context", GetErrorMessage(E_SYSTEM));
97
98
99         __pCodecCtx->bit_rate = DEFAULT_BIT_RATE;
100         __pCodecCtx->sample_rate = DEFAULT_SAMPLE_RATE;
101         __pCodecCtx->channels = DEFAULT_CHANNEL_COUNT;
102         __pCodecCtx->sample_fmt = AV_SAMPLE_FMT_FLT;
103         __pCodecCtx->profile = FF_PROFILE_AAC_LOW;
104         __pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
105
106         if (pOption != null)
107         {
108                 // The initialization values are given in the Hashmap
109                 std::unique_ptr<IMapEnumerator> pMapEnum(pOption->GetMapEnumeratorN());
110                 if (pMapEnum.get() != null)
111                 {
112                         while (pMapEnum.get()->MoveNext() == E_SUCCESS)
113                         {
114                                 pKey = dynamic_cast<Integer*>(pMapEnum.get()->GetKey());
115                                 pValue = dynamic_cast<Integer*>(pMapEnum.get()->GetValue());
116
117                                 if (pKey == null || pValue == null)
118                                 {
119                                         continue;
120                                 }
121
122                                 key = pKey->ToInt();
123                                 value = pValue->ToInt();
124                                 switch (key)
125                                 {
126                                 case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
127                                         SysTryCatch(NID_MEDIA, (value == 0 || value == 1 || value == 2), r = E_OUT_OF_RANGE,
128                                                            E_OUT_OF_RANGE, "[%s] Audio Channel Type %d is outof range",GetErrorMessage(E_OUT_OF_RANGE));
129                                         __pCodecCtx->channels = value;
130                                         break;
131
132                                 case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
133                                         SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
134                                                            "[%s] Audio Sample rate is out of range", GetErrorMessage(E_OUT_OF_RANGE));
135                                         __pCodecCtx->sample_rate = value;
136                                         break;
137
138                                 case MEDIA_PROPERTY_AUDIO_BIT_RATE:
139                                         SysTryCatch(NID_MEDIA, !(value < 0), r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
140                                                            "[%s] Audio Bit Rate is out of range",GetErrorMessage(E_OUT_OF_RANGE));
141                                         __pCodecCtx->bit_rate = value;
142                                         break;
143
144                                 default:
145                                         SysLog(NID_MEDIA,"[%s] Ignore option:%d", GetErrorMessage(E_INVALID_ARG),key);
146                                         break;
147                                 }
148                         }
149
150                 }
151         }
152
153         if ( __pCodecCtx->bit_rate * SAMPLE_SIZE / __pCodecCtx->sample_rate
154                  > __pCodecCtx->channels * BYTES_PER_SAMPLE)
155         {
156                 __pCodecCtx->bit_rate = (__pCodecCtx->channels * BYTES_PER_SAMPLE)
157                         / SAMPLE_SIZE * __pCodecCtx->sample_rate;
158         }
159
160         res = avcodec_open(__pCodecCtx, __pCodec);
161         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
162                            "[%s] avcodec open failed:%d", GetErrorMessage(E_SYSTEM), res);
163
164         if (__pCodecCtx->sample_fmt  == AV_SAMPLE_FMT_FLT)
165         {
166                 inputSize = __pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE;
167                 __pInputBuf = new (std::nothrow) byte[inputSize];
168                 SysTryCatch(NID_MEDIA, __pInputBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
169                            "[%s] Memory Allocation Failed", GetErrorMessage(E_OUT_OF_MEMORY));
170         }
171
172         __pInputFrame = avcodec_alloc_frame();
173         SysTryCatch(NID_MEDIA, __pInputFrame != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
174                            "[%s] Memory Allocation Failed", GetErrorMessage(E_OUT_OF_MEMORY));
175
176         __pInputFrame->nb_samples = __pCodecCtx->frame_size;
177         __pInputFrame->format = __pCodecCtx->sample_fmt;
178         __pInputFrame->channel_layout = __pCodecCtx->channel_layout;
179
180         return r;
181
182 CATCH:
183
184         if (__pCodecCtx != null)
185         {
186                 avcodec_close(__pCodecCtx);
187                 av_free(__pCodecCtx);
188                 __pCodecCtx = null;
189                 __pCodec = null;
190         }
191         return r;
192 }
193
194 result
195 _AacEncoder::Encode(const byte* srcBuf, int& srcBufLength, byte*& dstBuf, int& dstBufLength)
196 {
197         result r = E_SUCCESS;
198         int res = 0;
199         int outIndex = 0;
200         int samples = 0;
201         int minSrcBufLength = 0;
202         int minDstBufLength = FF_MIN_BUFFER_SIZE;
203         AVPacket outPacket;
204         outPacket.data = null;
205         int gotOutput = 0;
206
207         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
208
209         minSrcBufLength = __pCodecCtx->frame_size * S16_SAMPLE_SIZE * __pCodecCtx->channels;
210
211         SysTryCatch(NID_MEDIA, srcBuf != null && dstBuf != null, r = E_INVALID_ARG, E_INVALID_ARG,
212                            "[%s] Invalid argument is used: 0x%x %d %d 0x%x %d %d",
213                            GetErrorMessage(E_INVALID_ARG), srcBuf, srcBufLength, minSrcBufLength, dstBuf, dstBufLength, minDstBufLength);
214
215         //Partial frame encoding is supported hence no need of checking sourcebuf length.
216         SysTryCatch(NID_MEDIA, dstBufLength >= minDstBufLength,
217                            r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
218                            "[%s] Destination Buffer Length is less than FF_MIN_BUFFER_SIZE: 0x%x %d %d 0x%x %d %d",
219                            GetErrorMessage(E_OUT_OF_MEMORY), srcBuf, srcBufLength, minSrcBufLength, dstBuf, dstBufLength, minDstBufLength);
220
221         //Only AV_SAMPLE_FMT_FLT is supported by FFMpeg AAC Encoder hence Sample Format Conversion from S16 to Float
222         if (__pCodecCtx->sample_fmt  == AV_SAMPLE_FMT_FLT)
223         {
224                 if (!__pResampleContext)
225                 {
226                         __pResampleContext = av_audio_resample_init(__pCodecCtx->channels, __pCodecCtx->channels,
227                                                 __pCodecCtx->sample_rate, __pCodecCtx->sample_rate,
228                                                 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16,
229                                                 0, 0, 0, 0);
230                         SysTryCatch(NID_MEDIA, __pResampleContext != null, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
231                                            "[%s] av audio resample init failed",GetErrorMessage(E_UNSUPPORTED_FORMAT));
232
233                 }
234
235                 memset(__pInputBuf,0,__pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE);
236
237                 if(srcBufLength >= minSrcBufLength)
238                 {
239                         samples = audio_resample (__pResampleContext, (short *) __pInputBuf, (short *)srcBuf, __pCodecCtx->frame_size);
240                 }
241                 else
242                 {
243                         int sampleCount = srcBufLength/(__pCodecCtx->channels * S16_SAMPLE_SIZE);
244                         samples = audio_resample (__pResampleContext, (short *) __pInputBuf, (short *)srcBuf,sampleCount);
245
246                 }
247
248                 res = avcodec_fill_audio_frame(__pInputFrame, __pCodecCtx->channels,__pCodecCtx->sample_fmt,
249                         (const uint8_t*)__pInputBuf,__pCodecCtx->frame_size * __pCodecCtx->channels * FLT_SAMPLE_SIZE,0 );
250
251                 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
252                         "[%s] Fill Audio Frame failed %d", GetErrorMessage(E_SYSTEM));
253
254                 av_init_packet(&outPacket);
255                 outPacket.data = NULL;
256                 outPacket.size = 0;
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                         dstBufLength = outPacket.size;
267                         av_free_packet(&outPacket);
268                 }
269                 else
270                 {
271                         dstBufLength = 0;
272                 }
273         }
274
275         srcBufLength = 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