Tizen 2.0 Release
[framework/osp/media.git] / src / FMedia_H263Decoder.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 <FBaseSysLog.h>
23 #include "FMedia_Ffmpeg.h"
24 #include "FMedia_IVideoDecoder.h"
25 #include "FMedia_H263Decoder.h"
26
27 using namespace Tizen::Base;
28 using namespace Tizen::Io;
29 using namespace Tizen::Base::Collection;
30
31 namespace Tizen { namespace Media
32 {
33
34 _IVideoDecoder*
35 _H263Decoder_CreateInstance(void)
36 {
37         return new (std::nothrow) _H263Decoder();
38 }
39
40 _H263Decoder::_H263Decoder(void)
41 {
42         __pCodecCtx = null;
43         __pCodec = null;
44         __isDecodeCalled = false;
45 }
46
47 _H263Decoder::~_H263Decoder(void)
48 {
49         if (__pCodecCtx != null)
50         {
51                 avcodec_flush_buffers(__pCodecCtx);
52                 avcodec_close(__pCodecCtx);
53                 av_free(__pCodecCtx);
54                 __pCodecCtx = null;
55                 __pCodec = null;
56         }
57 }
58
59 result
60 _H263Decoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
61 {
62         result r = E_SUCCESS;
63         int res = 0;
64
65         SysAssertf((__pCodecCtx == null && __pCodec == null), " Already Constructed .");\r
66
67         avcodec_register_all();
68
69         __pCodecCtx = avcodec_alloc_context();
70         SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
71                             "[%s] AVCODEC Context Allcoation Failed",GetErrorMessage(E_SYSTEM));\r
72         __pCodec = avcodec_find_decoder(CODEC_ID_H263);
73         SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM,
74                            "[%s] AVCODEC Find Decoder Failed for CODEC_ID_H263",GetErrorMessage(E_SYSTEM));\r
75 \r
76         res = avcodec_open(__pCodecCtx, __pCodec);
77         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
78                             "[%s] AVCODEC Codec Open Failed for CODEC_ID_H263",GetErrorMessage(E_SYSTEM));\r
79
80         // AVCodecContext parameters
81         if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
82         {
83                 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
84         }
85
86         __pCodecCtx->debug_mv = 0; //set by user
87         __pCodecCtx->debug = 0; //set by user
88         __pCodecCtx->workaround_bugs = 1; //set by user
89         __pCodecCtx->lowres = 0; //set by user
90         __pCodecCtx->skip_frame = AVDISCARD_DEFAULT; //set by user
91         __pCodecCtx->skip_idct = AVDISCARD_DEFAULT; //set by user
92         __pCodecCtx->skip_loop_filter = AVDISCARD_DEFAULT; //set by user
93
94         return r;
95
96 CATCH:
97         if (__pCodecCtx != null)
98         {
99                 avcodec_close(__pCodecCtx);
100                 __pCodecCtx = null;
101                 __pCodec = null;
102         }
103         return r;
104 }
105
106 result
107 _H263Decoder::Decode(const byte* pSrcBuf, int& srcBufLength,
108                                          byte*& pDstBuf, int& dstBufLength, bool& gotFrame)
109 {
110         result r = E_SUCCESS;
111         int res = 0;
112         AVFrame* pVideoFrame = null;
113         AVPacket inputPacket;
114         int gotPicture = 0;
115         int remainingBytes = 0;
116         int srcOffset = 0;
117         int i = 0;
118         int offset = 0;
119
120         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");\r
121         SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && pDstBuf != null && srcBufLength > 0 && dstBufLength > 0),
122                                            E_INVALID_ARG, "Invalid argument is used. The argument is not valid");\r
123
124         av_init_packet(&inputPacket);
125         inputPacket.size = srcBufLength;
126         pVideoFrame = avcodec_alloc_frame();
127         SysTryCatch(NID_MEDIA, pVideoFrame != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
128                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
129
130         inputPacket.data = (uint8_t*) pSrcBuf;
131         // Decoding the video packet
132         remainingBytes = srcBufLength;
133
134         do
135         {
136                 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
137                 SysTryCatch(NID_MEDIA, res >= 0, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
138                                    "[%s] The input data format is not supported ", GetErrorMessage(E_UNSUPPORTED_FORMAT));\r
139
140                 remainingBytes -= res;
141                 inputPacket.data += res;
142                 inputPacket.size -= res;
143
144                 if (gotPicture)
145                 {
146                         __isDecodeCalled = true;
147                         if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only  yuv 420 case
148                         {
149                                 SysTryCatch(NID_MEDIA, dstBufLength >= (__pCodecCtx->height*__pCodecCtx->width*3)/2,
150                                                    r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
151                                                    "[%s] pDstBuf:%d %d %d",GetErrorMessage(E_OUT_OF_MEMORY),\r
152                                                    dstBufLength, __pCodecCtx->height, __pCodecCtx->width);
153                                 for (i = 0; i < __pCodecCtx->height; i++)
154                                 {
155                                         srcOffset = i * pVideoFrame->linesize[0];
156                                         offset = i * __pCodecCtx->width;
157                                         memcpy(pDstBuf + offset, pVideoFrame->data[0] + srcOffset, __pCodecCtx->width);
158                                 }
159                                 for (i = 0; i < __pCodecCtx->height / 2; i++)
160                                 {
161                                         srcOffset = i * pVideoFrame->linesize[1];
162                                         offset = (__pCodecCtx->height * __pCodecCtx->width) + (i * __pCodecCtx->width) / 2;
163                                         memcpy(pDstBuf + offset, pVideoFrame->data[1] + srcOffset, __pCodecCtx->width / 2);
164                                 }
165                                 for (i = 0; i < __pCodecCtx->height / 2; i++)
166                                 {
167                                         srcOffset = i * pVideoFrame->linesize[2];
168                                         offset = ((__pCodecCtx->height * __pCodecCtx->width * 5) / 4) + (i * __pCodecCtx->width) / 2;
169                                         memcpy(pDstBuf + offset, pVideoFrame->data[2] + srcOffset, __pCodecCtx->width / 2);
170                                 }
171                                 gotFrame = true;
172                                 srcBufLength = srcBufLength - remainingBytes;  //Input bytes used
173                                 dstBufLength = (__pCodecCtx->height * __pCodecCtx->width * 3) / 2;
174                         }
175                         break;
176                 }
177         }
178         while (remainingBytes);
179
180         if (!gotPicture)
181         {
182                 // "Trying for another decode"
183                 inputPacket.data = null;
184                 inputPacket.size = 0;
185                 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
186                 if (gotPicture)
187                 {
188                         // "Got Frame."
189                         __isDecodeCalled = true;
190                         if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P ) // handling only  yuv 420 case
191                         {
192                                 SysTryCatch(NID_MEDIA, dstBufLength >= (__pCodecCtx->height*__pCodecCtx->width*3)/2,
193                                                    r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
194                                                     "[%s] Decode Failed Insufficient destination buffer",GetErrorMessage(E_OUT_OF_MEMORY));                             \r
195                                 for (i = 0; i < __pCodecCtx->height; i++)
196                                 {
197                                         srcOffset = i * pVideoFrame->linesize[0];
198                                         offset = i * __pCodecCtx->width;
199                                         memcpy(pDstBuf + offset, pVideoFrame->data[0] + srcOffset, __pCodecCtx->width);
200                                 }
201                                 for (i = 0; i < __pCodecCtx->height / 2; i++)
202                                 {
203                                         srcOffset = i * pVideoFrame->linesize[1];
204                                         offset = (__pCodecCtx->height * __pCodecCtx->width) + (i * __pCodecCtx->width) / 2;
205                                         memcpy(pDstBuf + offset, pVideoFrame->data[1] + srcOffset, __pCodecCtx->width / 2);
206                                 }
207                                 for (i = 0; i < __pCodecCtx->height / 2; i++)
208                                 {
209                                         srcOffset = i * pVideoFrame->linesize[2];
210                                         offset = ((__pCodecCtx->height * __pCodecCtx->width * 5) / 4) + (i * __pCodecCtx->width) / 2;
211                                         memcpy(pDstBuf + offset, pVideoFrame->data[2] + srcOffset, __pCodecCtx->width / 2);
212                                 }
213                                 gotFrame = true;
214                                 srcBufLength = srcBufLength - remainingBytes;  //Input bytes used
215                                 dstBufLength = (__pCodecCtx->height * __pCodecCtx->width * 3) / 2;
216                         }
217                 }
218                 else
219                 {
220                         // "No Frame."
221                         srcBufLength = srcBufLength - remainingBytes;  //Input bytes used
222                         gotFrame = false;
223                 }
224         }
225         {
226                 av_free(pVideoFrame);
227         }
228         return r;
229
230 CATCH:
231         if (pVideoFrame != null)
232         {
233                 av_free(pVideoFrame);
234         }
235
236         SysLog(NID_MEDIA, "Error is %d.", res);
237         return r;
238 }
239
240 result
241 _H263Decoder::Probe(const byte* pSrcBuf, const int srcBufLength, int& width, int& height,
242                                         MediaPixelFormat& pixelFormat)
243 {
244         result r = E_SUCCESS;
245         int res = 0;
246         AVFrame* pVideoFrame = null;
247         AVPacket inputPacket;
248         int gotPicture = 0;
249         int remainingBytes = 0;
250
251         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");\r
252         SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && srcBufLength > 0), E_INVALID_ARG,
253                                            "Invalid argument is used. The argument is not valid");\r
254
255         av_init_packet(&inputPacket);
256         inputPacket.size = srcBufLength + FF_INPUT_BUFFER_PADDING_SIZE;
257         pVideoFrame = avcodec_alloc_frame();
258
259         SysTryCatch(NID_MEDIA, (pVideoFrame != null), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
260                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
261         inputPacket.data = (uint8_t*) pSrcBuf;
262
263         // Decoding the video packet
264         remainingBytes = inputPacket.size;
265
266         do
267         {
268                 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
269                 SysTryCatch(NID_MEDIA, res >= 0, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
270                                    "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
271
272                 if (gotPicture)
273                 {
274                         // "Got Frame."
275                         if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only  yuv 420 case
276                         {
277                                 width = __pCodecCtx->width;
278                                 height = __pCodecCtx->height;
279                                 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
280                         }
281                         break;
282                 }
283
284                 remainingBytes -= res;
285                 inputPacket.data += res;
286                 inputPacket.size -= res;
287         }
288         while (remainingBytes);
289
290         if (!gotPicture)
291         {
292                 inputPacket.data = null;
293                 inputPacket.size = 0;
294                 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
295                 if (gotPicture && res >= 0)
296                 {
297                         //  "Got Frame."
298                         if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only  yuv 420 case
299                         {
300                                 width = __pCodecCtx->width;
301                                 height = __pCodecCtx->height;
302                                 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
303                         }
304                 }
305                 else
306                 {
307                         r = E_UNSUPPORTED_FORMAT;
308                 }
309         }
310
311         if (pVideoFrame != null)
312         {
313                 av_free(pVideoFrame);
314         }
315         return r;
316
317 CATCH:
318         if (pVideoFrame != null)
319         {
320                 av_free(pVideoFrame);
321         }
322         return r;
323 }
324
325 result
326 _H263Decoder::Reset(void)
327 {
328         result r = E_SUCCESS;
329
330         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");\r
331         avcodec_flush_buffers(__pCodecCtx);
332         __isDecodeCalled = false;
333
334         return r;
335 }
336
337 result
338 _H263Decoder::GetValue(MediaPropertyType type, int& value) const
339 {
340         result r = E_SUCCESS;
341
342         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");\r
343         SysTryCatch(NID_MEDIA, __isDecodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
344                            "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
345         SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG,
346                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
347         SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
348                            r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
349                            "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
350
351         switch (type)
352         {
353         case MEDIA_PROPERTY_VIDEO_WIDTH:
354                 value = __pCodecCtx->width;
355         break;
356
357         case MEDIA_PROPERTY_VIDEO_HEIGHT:
358                 value = __pCodecCtx->height;
359         break;
360
361         case MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT:
362                 value = MEDIA_PIXEL_FORMAT_YUV420P;
363         break;
364
365         default:
366                 return E_OBJ_NOT_FOUND;
367                 break;
368         }
369         return r;
370
371 CATCH:
372         return r;
373 }
374
375 result
376 _H263Decoder::GetValue(MediaPropertyType type, float& value) const
377 {
378         result r = E_SUCCESS;
379
380         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
381         SysTryCatch(NID_MEDIA, __isDecodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
382                             "[%s] The instance is in invalid state",GetErrorMessage(E_INVALID_STATE));\r
383         SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG,
384                            "[%s] Invalid argument is used. The argument is not valid",GetErrorMessage(E_INVALID_ARG));\r
385         SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH || type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
386                            r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,  "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
387
388         return E_OBJ_NOT_FOUND;
389
390 CATCH:
391         return r;
392 }
393
394 Tizen::Base::Collection::IListT<MediaPropertyType>*
395 _H263Decoder::GetSupportedPropertyListN(void) const
396 {
397         result r = E_SUCCESS;
398
399         ArrayListT<MediaPropertyType>* pPropList = new (std::nothrow) ArrayListT<MediaPropertyType>;
400         SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
401                            "[%s] Memory Allocation  Failed ",GetErrorMessage(E_OUT_OF_MEMORY));\r
402         pPropList->Add(MEDIA_PROPERTY_VIDEO_WIDTH);
403         pPropList->Add(MEDIA_PROPERTY_VIDEO_HEIGHT);
404         pPropList->Add(MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT);
405         SetLastResult(r);
406         return pPropList;
407
408 CATCH:
409         return null;
410 }
411
412 bool
413 _H263Decoder::IsPropertySupported(MediaPropertyType type) const
414 {
415         result r = E_SUCCESS;
416         ClearLastResult();
417
418         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
419         SysTryCatch(NID_MEDIA, (type == MEDIA_PROPERTY_VIDEO_WIDTH || type == MEDIA_PROPERTY_VIDEO_HEIGHT
420                                                    || type == MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT),
421                            r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
422                           "[%s] The instance is not available ",GetErrorMessage(E_OBJ_NOT_FOUND));\r
423         SetLastResult(r);
424         return true;
425
426 CATCH:
427         return false;
428 }
429
430 }} // Tizen::Media