2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <vorbis/codec.h>
20 #include <FBaseColArrayListT.h>
21 #include <FBaseColHashMap.h>
22 #include <FBaseColHashMapT.h>
23 #include <FBaseUtilMath.h>
24 #include <FMediaTypes.h>
25 #include <FMediaAudioTypes.h>
26 #include <FBaseSysLog.h>
27 #include "FMedia_VorbisDecoder.h"
29 using namespace Tizen::Base;
30 using namespace Tizen::Io;
31 using namespace Tizen::Base::Collection;
32 using namespace Tizen::Base::Utility;
34 namespace Tizen { namespace Media
40 _OggStream(int serial)
43 memset((void *)&mState, 0, sizeof(mState));
48 ogg_stream_clear(&mState);
52 ogg_stream_state mState;
58 _VorbisDecoder_CreateInstance()
60 return new (std::nothrow) _VorbisDecoder();
63 _VorbisDecoder::_VorbisDecoder(void)
65 __isConstructed = false;
66 memset(&__vorbisBlock, 0, sizeof(vorbis_block));
67 memset(&__vorbisComment, 0, sizeof(vorbis_comment));
68 memset(&__vorbisInfo, 0, sizeof(vorbis_info));
69 memset(&__vorbisState, 0, sizeof(vorbis_dsp_state));
70 memset(&__state, 0, sizeof(__state));
71 __isHeaderDecoded = false;
75 __maxOffsetLength = 0;
79 _VorbisDecoder::~_VorbisDecoder(void)
81 __isConstructed = false;
82 __isHeaderDecoded = false;
84 // Eliminate the memory leak for stream* previously added in hashmap
86 IMapEnumeratorT<int,_OggStream*> * pEnum = __streamMap.GetMapEnumeratorN();
89 _OggStream* pValue = null;
90 while (pEnum->MoveNext() == E_SUCCESS)
92 pEnum->GetValue(pValue);
101 __streamMap.RemoveAll();
103 // Clear calls for the vorbis decoder library to avoid memory leak.
104 vorbis_block_clear(&__vorbisBlock);
105 vorbis_dsp_clear(&__vorbisState);
106 vorbis_comment_clear(&__vorbisComment);
107 vorbis_info_clear(&__vorbisInfo);
110 ogg_sync_clear(&__state);
114 _VorbisDecoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
116 result r = E_SUCCESS;
118 SysAssertf( __isConstructed == false, " Already Constructed .");
120 vorbis_info_init(&__vorbisInfo);
121 vorbis_comment_init(&__vorbisComment);
122 r = __streamMap.Construct();
123 SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = E_SYSTEM, E_SYSTEM,
124 "[%s] map construct Failed",GetErrorMessage(E_SYSTEM));
125 __isConstructed = true;
134 _VorbisDecoder::ParseOggStream(void)
138 result r = E_SUCCESS;
139 char* pBuffer = null;
141 // " ParseOggStream offSet & maxOffSetLength
142 SysTryCatch(NID_MEDIA, __offset != __maxOffsetLength, r = E_END_OF_FILE, E_END_OF_FILE,
143 "[%s] Reached End of File",GetErrorMessage(E_END_OF_FILE));
145 while (ogg_sync_pageout(&__state, &page) != 1)
147 pBuffer = ogg_sync_buffer(&__state, PAGE_SIZE);
148 SysTryCatch(NID_MEDIA, pBuffer != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
149 "[%s] Memory Allocation Failed ",GetErrorMessage(E_OUT_OF_MEMORY));
150 if ( !(__offset + PAGE_SIZE > __maxOffsetLength))
152 memcpy(pBuffer, __pBuf + __offset, PAGE_SIZE);
153 __offset += PAGE_SIZE;
154 ogg_sync_wrote(&__state, PAGE_SIZE);
158 memcpy(pBuffer, __pBuf + __offset, __maxOffsetLength - __offset );
159 __offset = __maxOffsetLength;
160 ogg_sync_wrote(&__state, PAGE_SIZE);
161 res = ogg_sync_pageout(&__state, &page);
162 SysTryCatch(NID_MEDIA, res == 1, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
163 "[%s] The input data format is not supported or Reached End of File ",GetErrorMessage(E_UNSUPPORTED_FORMAT));
168 __serial = ogg_page_serialno(&page);
170 if (ogg_page_bos(&page))
172 // " page is the beginning of a bitstream"
173 __pStream = new (std::nothrow) _OggStream(__serial);
174 SysTryCatch(NID_MEDIA, (__pStream != null), r = E_SYSTEM, E_SYSTEM,
175 "[E_SYSTEM]__streamMap.GetValue Failed",GetErrorMessage(E_SYSTEM));
176 res = ogg_stream_init(&__pStream->mState, __serial);
177 SysTryCatch(NID_MEDIA, (res == 0), r = E_SYSTEM, E_SYSTEM,
178 "[%s] ogg_stream_init:", GetErrorMessage(E_SYSTEM));
180 //All the hash map elements will be removed in the destructor
181 __streamMap.Add(__serial,__pStream);
185 _OggStream* pTemp = null;
186 r = __streamMap.GetValue(__serial, pTemp);
187 SysTryCatch(NID_MEDIA, (r == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
188 "[%s] __streamMap.GetValue Failed", GetErrorMessage(r));
189 SysTryCatch(NID_MEDIA, (pTemp != null), r = E_SYSTEM, E_SYSTEM,
190 "[%s] __streamMap.GetValue Failed", GetErrorMessage(E_SYSTEM));
194 ogg_stream_pagein(&__pStream->mState, &page);
202 _VorbisDecoder::SetStreamHeader(void)
206 result r = E_SUCCESS;
207 ogg_packet oggPacket;
210 r = ParseOggStream();
211 SysTryCatch(NID_MEDIA, (r == E_SUCCESS), , r,
212 "[%s] ParseOggStream Failed", GetErrorMessage(r));
214 for (headerCount = 0; headerCount < HEADER_COUNT;)
216 res = ogg_stream_packetout(&__pStream->mState, &oggPacket);
219 r = ParseOggStream();
220 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r,
221 "[%s] ParseOggStream Failed", GetErrorMessage(r))
222 res = ogg_stream_packetout(&__pStream->mState, &oggPacket);
224 SysTryCatch(NID_MEDIA, (res > 0), r = E_SYSTEM, E_SYSTEM,
225 "[%s] Failed to get a packet");
227 res = vorbis_synthesis_headerin(&__vorbisInfo, &__vorbisComment,
229 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
230 "[%s] vorbis_synthesis_headerin Failed", GetErrorMessage(E_SYSTEM));
240 _VorbisDecoder::Decode(const byte* srcBuf, int srcBufSize, int& srcBufUsed,
241 byte* dstBuf, int dstBufSize, int& dstBufUsed)
243 result r = E_SUCCESS;
245 ogg_packet oggPacket;
251 SysTryCatch(NID_MEDIA, ( __isConstructed == true), r = E_INVALID_STATE, E_INVALID_STATE,
252 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
253 SysTryCatch(NID_MEDIA, ( srcBuf != null && srcBufSize >= 0), r = E_INVALID_STATE, E_INVALID_STATE,
254 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
256 __pBuf = (byte*) srcBuf;
257 __maxOffsetLength = srcBufSize;
260 if (__isHeaderDecoded != true)
262 res = ogg_sync_init(&__state);
263 SysTryCatch(NID_MEDIA, (res == 0), r = E_SYSTEM, E_SYSTEM,
264 "[%s] ogg_sync_init Failed", GetErrorMessage(E_SYSTEM));
266 r = SetStreamHeader();
267 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r,
268 "[%s] Failed to get a packet", GetErrorMessage(E_SYSTEM));
270 res = vorbis_synthesis_init(&__vorbisState, &__vorbisInfo);
271 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
272 "[%s] vorbis_synthesis_init Failed", GetErrorMessage(E_SYSTEM));
273 res = vorbis_block_init(&__vorbisState, &__vorbisBlock);
274 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
275 "[%s] vorbis_block_init Failed", GetErrorMessage(E_SYSTEM));
276 __isHeaderDecoded = true;
279 // " Decoding Vorbis Audio "
282 res = ogg_stream_packetout(&__pStream->mState, &oggPacket);
285 r = ParseOggStream();
286 SysTryCatch(NID_MEDIA, r == E_SUCCESS, , r,
287 "[%s] Failed to get a packet", GetErrorMessage(E_SYSTEM));
288 res = ogg_stream_packetout(&__pStream->mState, &oggPacket);
292 continue; //no block required here , this is a continue statement.
295 res = vorbis_synthesis(&__vorbisBlock, &oggPacket);
296 if (res == OV_ENOTAUDIO || res == OV_EBADPACKET)
298 continue; //no block required here , this is a continue statement.
300 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
301 "[%s] vorbis_synthesis Failed", GetErrorMessage(E_SYSTEM));
303 res = vorbis_synthesis_blockin(&__vorbisState, &__vorbisBlock);
304 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
305 "[%s] vorbis_synthesis_blockin Failed", GetErrorMessage(E_SYSTEM));
307 samples = vorbis_synthesis_pcmout(&__vorbisState, &pcm);
310 ptr = (short*) (dstBuf + dstOffset);
311 SysTryCatch(NID_MEDIA, dstBufSize >= (samples * __vorbisInfo.channels * sizeof(short)),
312 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
313 "[%s] Failed to get a packet", GetErrorMessage(E_SYSTEM));
314 for (int i = 0; i < samples; ++i)
316 for (int j = 0; j < __vorbisInfo.channels; ++j)
318 int v = static_cast<int>(Tizen::Base::Utility::Math::Floor(0.5 + pcm[j][i] * 32767.0));
331 res = vorbis_synthesis_read(&__vorbisState, samples);
332 SysTryCatch(NID_MEDIA, res == E_SUCCESS, r = E_INVALID_ARG, E_INVALID_ARG,
333 "[%s] Decode Failed", GetErrorMessage(E_SYSTEM));
335 dstBufUsed = (samples * __vorbisInfo.channels * sizeof(short));
336 srcBufUsed = __offset;
340 if ( r == E_UNSUPPORTED_FORMAT && __isHeaderDecoded && srcBufSize < PAGE_SIZE )
342 srcBufUsed = __offset;
351 _VorbisDecoder::Probe(const byte* srcBuf, const int srcBufLength,
352 Tizen::Media::AudioSampleType& sampleType,
353 Tizen::Media::AudioChannelType& channelType, int& sampleRate)
355 result r = E_SUCCESS;
358 SysTryCatch(NID_MEDIA, (__isConstructed == true), r = E_INVALID_STATE, E_INVALID_STATE,
359 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
360 SysTryCatch(NID_MEDIA, (srcBuf != null && srcBufLength > 0), r = E_INVALID_ARG, E_INVALID_ARG,
361 "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));
363 __pBuf = (byte*) srcBuf;
364 __maxOffsetLength = srcBufLength;
367 res = ogg_sync_init(&__state);
368 SysTryCatch(NID_MEDIA, (res == 0), r = E_SYSTEM, E_SYSTEM,
369 "[%s] ogg_sync_init Failed", GetErrorMessage(E_SYSTEM));
371 r = SetStreamHeader();
372 SysTryCatch(NID_MEDIA, (r == E_SUCCESS), , r,
373 "[%s] ParseOggStream Failed", GetErrorMessage(r));
375 res = vorbis_synthesis_init(&__vorbisState, &__vorbisInfo);
376 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
377 "[%s]vorbis_synthesis_init Failed", GetErrorMessage(E_SYSTEM));
378 res = vorbis_block_init(&__vorbisState, &__vorbisBlock);
379 SysTryCatch(NID_MEDIA, (res == E_SUCCESS), r = E_SYSTEM, E_SYSTEM,
380 "[%s]vorbis_block_init Failed", GetErrorMessage(E_SYSTEM));
382 channelType = (Tizen::Media::AudioChannelType)__vorbisInfo.channels;
383 sampleType = AUDIO_TYPE_PCM_S16_LE;
384 sampleRate = __vorbisInfo.rate;
386 // Eliminate the memory leak for stream* previously added in hashmap
388 IMapEnumeratorT<int,_OggStream*> * pEnum = __streamMap.GetMapEnumeratorN();
391 _OggStream* pValue = null;
392 while (pEnum->MoveNext() == E_SUCCESS)
394 pEnum->GetValue(pValue);
403 __streamMap.RemoveAll();
405 // Clear calls for the vorbis decoder library to avoid memory leak.
406 vorbis_block_clear(&__vorbisBlock);
407 vorbis_dsp_clear(&__vorbisState);
408 vorbis_comment_clear(&__vorbisComment);
409 vorbis_info_clear(&__vorbisInfo);
411 // call to avoid memory leak
412 ogg_sync_clear(&__state);
414 vorbis_info_init(&__vorbisInfo);
415 vorbis_comment_init(&__vorbisComment);
424 _VorbisDecoder::Reset(void)
426 result r = E_SUCCESS;
429 SysTryCatch(NID_MEDIA, (__isConstructed == true), r = E_INVALID_STATE, E_INVALID_STATE,
430 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
431 vorbis_info_init(&__vorbisInfo);
432 vorbis_comment_init(&__vorbisComment);
433 res = vorbis_synthesis_restart(&__vorbisState);
434 __isHeaderDecoded = false;
435 SysTryCatch(NID_MEDIA, res == E_SUCCESS, r = E_INVALID_STATE, E_INVALID_STATE,
436 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
444 _VorbisDecoder::GetValue(MediaPropertyType type, int& value) const
446 result r = E_SUCCESS;
448 SysTryCatch(NID_MEDIA, (__isConstructed == true), r = E_INVALID_STATE, E_INVALID_STATE,
449 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
450 SysTryCatch(NID_MEDIA, 0 < type, r = E_INVALID_ARG, E_INVALID_ARG,
451 "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));
452 SysTryCatch(NID_MEDIA, (__isHeaderDecoded == true), r = E_INVALID_STATE, E_INVALID_STATE,
453 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
457 case MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE:
458 switch (__vorbisInfo.channels)
461 value = AUDIO_CHANNEL_TYPE_NONE;
465 value = AUDIO_CHANNEL_TYPE_MONO;
469 value = AUDIO_CHANNEL_TYPE_STEREO;
477 case MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE:
478 value = AUDIO_TYPE_PCM_S16_LE;
481 case MEDIA_PROPERTY_AUDIO_SAMPLE_RATE:
482 value = __vorbisInfo.rate;
486 return E_OBJ_NOT_FOUND;
496 _VorbisDecoder::GetValue(MediaPropertyType type, float& value) const
498 result r = E_SUCCESS;
500 SysTryCatch(NID_MEDIA, (__isConstructed == true), r = E_INVALID_STATE, E_INVALID_STATE,
501 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
502 SysTryCatch(NID_MEDIA, type < 0, r = E_INVALID_ARG, E_INVALID_ARG,
503 "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));
504 SysTryCatch(NID_MEDIA, type < MEDIA_PROPERTY_VIDEO_WIDTH || type >= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
505 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
506 "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));
507 SysTryCatch(NID_MEDIA, (__isHeaderDecoded == true), r = E_INVALID_STATE, E_INVALID_STATE,
508 "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));
510 return E_OBJ_NOT_FOUND;
516 Tizen::Base::Collection::IListT<MediaPropertyType>*
517 _VorbisDecoder::GetSupportedPropertyListN(void) const
519 result r = E_SUCCESS;
520 ArrayListT<MediaPropertyType>* pPropList = new (std::nothrow) ArrayListT<MediaPropertyType>;
522 SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
523 "[%s] Memory Allocation Failed ",GetErrorMessage(E_OUT_OF_MEMORY));
524 pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_RATE);
525 pPropList->Add(MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE);
526 pPropList->Add(MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE);
535 _VorbisDecoder::IsPropertySupported(MediaPropertyType type) const
537 result r = E_SUCCESS;
539 SysTryCatch(NID_MEDIA, (type == MEDIA_PROPERTY_AUDIO_SAMPLE_RATE
540 || type == MEDIA_PROPERTY_AUDIO_CHANNEL_TYPE
541 || type == MEDIA_PROPERTY_AUDIO_SAMPLE_TYPE),
542 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
543 "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));