merge with master
[framework/osp/image-core.git] / src / FMedia_BmpDecoder.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 /**
19  * @file   FMedia_BmpDecoder.c
20  * @brief  This file contains the implementation of _BmpDecoder class.
21  */
22 #include <unique_ptr.h>
23 #include <FBaseSysLog.h>
24 #include <FMediaImageTypes.h>
25 #include "FMedia_Ffmpeg.h"
26 #include "FMedia_BmpDecoder.h"
27 #include "FMedia_ImageUtil.h"
28
29 using namespace Tizen::Io;
30 using namespace Tizen::Base::Collection;
31
32 namespace Tizen { namespace Media
33 {
34
35 static const int _INPUT_BUFFER_PADDING_SIZE = FF_INPUT_BUFFER_PADDING_SIZE;
36
37 _BmpDecoder::_BmpDecoder(void)
38         : __pCodecCtx(null)
39         , __pCodec(null)
40         , __pVideoFrame(null)
41         , __pSrcBuf(null)
42         , __srcLength(0)
43         , __pixelFormat(MEDIA_PIXEL_FORMAT_NONE)
44 {
45 }
46
47 _BmpDecoder::~_BmpDecoder(void)
48 {
49         if (__pCodecCtx)
50         {
51                 avcodec_flush_buffers(__pCodecCtx);
52                 avcodec_close(__pCodecCtx);
53                 av_free(__pCodecCtx);
54         }
55
56         if (__pVideoFrame)
57         {
58                 av_free(__pVideoFrame);
59         }
60 }
61
62 result
63 _BmpDecoder::OpenCodec(void)
64 {
65         result r = E_SUCCESS;
66         int res = 0;
67
68         avcodec_register_all();
69
70         __pCodec = avcodec_find_decoder(CODEC_ID_BMP);
71         SysTryReturnResult(NID_MEDIA, __pCodec != null, E_UNSUPPORTED_CODEC, "Failed to find bmp decoder.");
72
73         __pCodecCtx = avcodec_alloc_context3(__pCodec);
74         SysTryReturnResult(NID_MEDIA, __pCodecCtx != null, E_OUT_OF_MEMORY, "context allocation failed.");
75
76         res = avcodec_open2(__pCodecCtx, __pCodec, null);
77         SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
78                            "[E_SYSTEM] Failed to open bmp decoder.");
79
80         // AVCodecContext parameters
81         if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
82         {
83                 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
84         }
85
86         // Allocate memory for decoder output.
87         __pVideoFrame = avcodec_alloc_frame();
88         SysTryCatch(NID_MEDIA, __pVideoFrame != null, r = E_OUT_OF_MEMORY,
89                            E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Output buffer allocation failed");
90
91         return r;
92
93 CATCH:
94         CloseCodec();
95
96         return r;
97 }
98
99 void
100 _BmpDecoder::CloseCodec(void)
101 {
102         if (__pCodecCtx)
103         {
104                 avcodec_close(__pCodecCtx);
105                 av_free(__pCodecCtx);
106                 __pCodecCtx = null;
107                 __pCodec = null;
108         }
109
110         //__inputPacket.size = 0;
111         //SAFE_DELETE_ARRAY(__inputPacket.data);
112 }
113
114 result
115 _BmpDecoder::Construct(const byte* buffer, int length, MediaPixelFormat pixelFormat)
116 {
117         result r = E_SUCCESS;
118         // uint8_t* pInputData = null;
119         int res = 0;
120         int gotPicture = 0;
121         AVPacket pkt;
122
123         SysTryCatch(NID_MEDIA, buffer != null, r = E_INVALID_ARG, E_INVALID_ARG,
124                            "[E_INVALID_ARG] buffer is null.");
125
126         SysTryCatch(NID_MEDIA, length > 0, r = E_INVALID_ARG, E_INVALID_ARG,
127                            "[E_INVALID_ARG] length is zero.");
128
129         // _TRY_CATCH_INVALID_STATE(!__pCodecCtx);
130         SysTryCatch(NID_MEDIA, !__pCodecCtx, r = E_INVALID_STATE, E_INVALID_STATE,
131                            "[E_INVALID_STATE] Already Constructed");
132
133         // Initialize ffmpeg.
134         r = OpenCodec();
135         SysTryCatch(NID_MEDIA, r == E_SUCCESS, r = E_SYSTEM, E_SYSTEM,
136                            "[E_SYSTEM] Could not initialize FFMPEG.");
137
138         // Forming the input packet for decoder.
139         av_init_packet(&pkt);
140         // Decoder input must end in a padding of 8 zeroes.
141         pkt.size = length + _INPUT_BUFFER_PADDING_SIZE;
142         __pSrcBuf.reset(new (std::nothrow) byte[pkt.size]);
143         SysTryCatch(NID_MEDIA, __pSrcBuf.get() != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
144                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for input frame.", pkt.size);
145         memcpy(__pSrcBuf.get(), buffer, length);
146         memset(__pSrcBuf.get() + length, 0, _INPUT_BUFFER_PADDING_SIZE);
147         pkt.data = (uint8_t*)__pSrcBuf.get();
148
149         // NOTE:
150         //         Decoding has been done in Construct instead of in DecodeN
151         //         function because GetDimension is called in the _ImageDecoderImpl
152         //         function, before decode. Since dimensions are not available
153         //         till the image is decoded, decode is done here.
154         //       If "avcodec_decode_video2" must be moved to "DecodeN",
155         //         then the sequence of calls in _ImageDecoderImpl should be changed.
156         //
157
158         res = avcodec_decode_video2(__pCodecCtx, __pVideoFrame, &gotPicture, &pkt);
159         // avcodec_decode_video2 returns res greater than zero on success.
160         SysTryCatch(NID_MEDIA, res > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Decode Failed");
161         // The value of gotPicture is non zero if a frame is found.
162         SysTryCatch(NID_MEDIA, gotPicture, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Decode Failed");
163
164         // Dimensions are __pCodecCtx->width and __pCodecCtx->height.
165         return r;
166
167 CATCH:
168         CloseCodec();
169         return r;
170 }
171
172 byte*
173 _BmpDecoder::DecodeN(int& outLength)
174 {
175         int resFfmpeg = 0;
176
177         std::unique_ptr<byte[]> pOutBuf;
178
179         SysTryReturn(NID_MEDIA, __pCodecCtx, null, E_INVALID_STATE,
180                            "[E_INVALID_STATE] Not Constructed");
181
182         // The following steps convert the decoder output to RGB565LE
183         // format, irrespective of decoder output format.
184         // Also required to eliminate the "padding" present in decoder
185         // output data.
186         //
187         outLength = avpicture_get_size(__pCodecCtx->pix_fmt, __pCodecCtx->width,
188                                                                 __pCodecCtx->height);
189         SysTryReturn(NID_MEDIA, 0 < outLength, null, E_OUT_OF_MEMORY, "FFMPEG returned buffer size as zero.");
190
191         pOutBuf.reset(new (std::nothrow) byte[outLength]);
192         SysTryReturn(NID_MEDIA, pOutBuf.get() != null, null, E_OUT_OF_MEMORY,
193                            "[E_OUT_OF_MEMORY] Memory allocation of %d bytes for output buffer failed!", outLength);
194         __pixelFormat = _ImageUtil::ToMediaPixelFormatFromFfmpeg(__pCodecCtx->pix_fmt);
195
196         resFfmpeg = av_image_copy_to_buffer(pOutBuf.get(), outLength,
197                                                                 (const uint8_t * const*)__pVideoFrame->data, (const int*)__pVideoFrame->linesize,
198                                                                 __pCodecCtx->pix_fmt, __pCodecCtx->width, __pCodecCtx->height, 1);
199
200         SysTryReturn(NID_MEDIA, resFfmpeg >= 0, null, E_SYSTEM,
201                            "[E_SYSTEM] Could not copy image data to buffer!!");
202
203         SetLastResult(E_SUCCESS);
204         return pOutBuf.release();
205 }
206
207 result
208 _BmpDecoder::SetDecodingRegion(int x, int y, int width, int height)
209 {
210         // result r = E_SUCCESS;
211
212         // SysTryCatch(NID_MEDIA, __isConstructed, r = E_INVALID_STATE,
213         //  E_INVALID_STATE, "[E_INVALID_STATE] Instance is not constructed.");
214         // TODO
215
216 // CATCH:
217         return E_UNSUPPORTED_OPERATION;
218 }
219
220 result
221 _BmpDecoder::GetDimension(int& width, int& height)
222 {
223         SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not Constructed.");
224
225         SysTryReturnResult(NID_MEDIA, __pCodecCtx->width > 0 && __pCodecCtx->height > 0, E_INVALID_STATE,
226                         "Invalid dimensions : (%d x %d)", __pCodecCtx->width, __pCodecCtx->height);
227
228         width = __pCodecCtx->width;
229         height = __pCodecCtx->height;
230
231         return E_SUCCESS;
232 }
233
234 MediaPixelFormat
235 _BmpDecoder::GetPixelFormat(void)
236 {
237         MediaPixelFormat pixel_format = MEDIA_PIXEL_FORMAT_NONE;
238
239         SysTryReturn(NID_MEDIA, __pCodecCtx, pixel_format, E_INVALID_STATE,
240                                 "[E_INVALID_STATE] Not constructed");
241
242         return __pixelFormat;
243 }
244
245 result
246 _BmpDecoder::SetScaleDown(int scaleDown)
247 {
248         result r = E_SUCCESS;
249
250         SysTryReturn(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, E_INVALID_STATE,
251                                 "[E_INVALID_STATE] Not Constructed.");
252         // TODO
253         return r;
254 }
255
256 result
257 _BmpDecoder::GetValue(const Tizen::Base::String& key, Tizen::Base::Object &value)
258 {
259         return E_UNSUPPORTED_OPERATION;
260 }
261
262 }} // Tizen::Media