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