Fixed unsuppoted jpeg decoder exception code
[framework/osp/image-core.git] / src / FMedia_JpegDecoder.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_JpegDecoder.cpp
20  * @brief This file contains the implementation of _JpegDecoder class.
21  */
22 #include <stdio.h>
23 #include <setjmp.h>
24 #include <jpeglib.h>
25 #include <stdlib.h>
26 #include <FMediaImageTypes.h>
27 #include <FBaseSysLog.h>
28 #include "FMedia_JpegDecoder.h"
29
30 namespace Tizen { namespace Media
31 {
32
33 _JpegDecoder::_JpegDecoder(void)
34 {
35         __pSrcBuf = null;
36         __srcBufSize = 0;
37         __srcWidth = 0;
38         __srcHeight = 0;
39         __decodingRectX = 0;
40         __decodingRectY = 0;
41         __decodingRectWidth = 0;
42         __decodingRectHeight = 0;
43         __isDecodeRegionEnabled = false;
44         __scale = 0;
45         __pDec = null;
46         __pErr = null;
47         __pJmp = null;
48 }
49
50 _JpegDecoder::~_JpegDecoder(void)
51 {
52         // SAFE_DELETE_ARRAY(__pSrcBuf);
53         if (__pDec != null)
54         {
55                 jpeg_destroy_decompress(__pDec);
56         }
57
58         if (__pDec)
59         {
60                 delete __pDec;
61         }
62         if (__pErr)
63         {
64                 delete __pErr;
65         }
66         if (__pJmp)
67         {
68                 delete __pJmp;
69         }
70 }
71
72 void
73 _JpegDecoder::JpegErrorExitStatic(struct jpeg_common_struct * pDecInfo)
74 {
75         if (pDecInfo != null)
76         {
77                 _JpegDecoder *pDec = (_JpegDecoder*)pDecInfo->client_data;
78                 if (pDec)
79                 {
80                         pDec->JpegErrorExit();
81                 }
82         }
83 }
84
85 void
86 _JpegDecoder::JpegErrorExit(void)
87 {
88         longjmp(__pJmp, 1);
89 }
90
91 result
92 _JpegDecoder::Construct(const byte* buffer, int length, MediaPixelFormat pixelFormat)
93 {
94         result r = E_SUCCESS;
95
96         SysTryReturnResult(NID_MEDIA, __pDec == null, E_INVALID_STATE, "Already constructed");
97
98         // TODO: do not copy the source data
99         //__pSrcBuf = new (std::nothrow) byte[length];
100         //SysTryCatch(NID_MEDIA, __pSrcBuf != null, r = E_SYSTEM, E_SYSTEM,
101         //                 "[E_SYSTEM] new byte:%d", length);
102         // memcpy(__pSrcBuf, buffer, length);
103         __pSrcBuf = (byte*)buffer;
104         __srcBufSize = length;
105
106         __pDec = new (std::nothrow) jpeg_decompress_struct;
107         SysTryCatch(NID_MEDIA, __pDec != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
108                            "[E_OUT_OF_MEMORY] new ", sizeof(jpeg_decompress_struct));
109         __pErr = new (std::nothrow) jpeg_error_mgr;
110         SysTryCatch(NID_MEDIA, __pErr != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
111                            "[E_OUT_OF_MEMORY] new ", sizeof(jpeg_error_mgr));
112         __pJmp = new (std::nothrow) __jmp_buf_tag;
113         SysTryCatch(NID_MEDIA, __pJmp != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
114                            "[E_OUT_OF_MEMORY] new ", sizeof(__jmp_buf_tag));
115
116         memset(__pDec, 0, sizeof(jpeg_decompress_struct));
117         memset(__pErr, 0, sizeof(jpeg_error_mgr));
118         memset(__pJmp, 0, sizeof(__jmp_buf_tag));
119
120         // Initialize
121         __pDec->err = jpeg_std_error(__pErr);
122         __pErr->error_exit = JpegErrorExitStatic;
123         __pDec->client_data = this;
124
125         SysTryCatch(NID_MEDIA, !setjmp(__pJmp), r = E_INVALID_DATA, E_INVALID_DATA,
126                            "[E_INVALID_DATA] error jump");
127
128         jpeg_create_decompress(__pDec);
129
130         // Specify data source for decompression
131         jpeg_mem_src(__pDec, (JOCTET*) __pSrcBuf, __srcBufSize);
132
133         // Read file header, set default decompression parameters
134         jpeg_read_header(__pDec, TRUE);
135
136         __srcWidth = __pDec->image_width;
137         __srcHeight = __pDec->image_height;
138
139         return E_SUCCESS;
140
141 CATCH:
142         //SAFE_DELETE_ARRAY(__pSrcBuf);
143         if (__pDec)
144         {
145                 jpeg_destroy_decompress(__pDec);
146         }
147         return r;
148 }
149
150 byte*
151 _JpegDecoder::DecodeN(int& length)
152 {
153         int buffSize = 0;
154         int planarSize = 0;
155         int h = 0;
156         byte* pReturnBuf = null;
157         int outY = 0;
158         int outX = 0;
159         byte* outBuf = null;
160         result r = E_SUCCESS;
161
162         SysTryCatch(NID_MEDIA, !setjmp(__pJmp), r = E_INVALID_DATA, E_INVALID_DATA,
163                            "[E_INVALID_DATA] error jump");
164
165         // Set decoding option
166         if (__pDec->jpeg_color_space == JCS_GRAYSCALE)
167         {
168                 __pDec->out_color_space = JCS_GRAYSCALE;
169         }
170         else // YUV444
171         {
172                 __pDec->out_color_space = JCS_YCbCr;
173         }
174
175         // Start decompressor
176         jpeg_start_decompress(__pDec);
177
178         // Write output buffer
179         __srcWidth = __pDec->output_width;
180         __srcHeight = __pDec->output_height;
181
182         if (__pDec->output_components == 1)  // for grayscale
183         {
184                 if (__isDecodeRegionEnabled == true)
185                 {
186                         int row_stride = __pDec->output_width;
187                         buffSize = __decodingRectWidth * __decodingRectHeight * 3;
188                         length = buffSize;
189                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
190
191                         pReturnBuf = new (std::nothrow) byte[buffSize];
192                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
193                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
194
195                         // Initialize cb and cr to 128, since they need not be considered for gray scale image.
196                         memset(pReturnBuf, 128, buffSize);
197                         outBuf = pReturnBuf;
198
199                         while (__pDec->output_scanline < (__decodingRectY + __decodingRectHeight))
200                         {
201                                 jpeg_read_scanlines(__pDec, buffer, 1);
202                                 if (h >= __decodingRectY)
203                                 {
204                                         outX = 0;
205                                         for (int x = __decodingRectX; x < __decodingRectX + __decodingRectWidth; x++)
206                                         {
207                                                 JSAMPLE* p = buffer[0] + x;
208
209                                                 // YUV444  -> YUV444p
210                                                 pReturnBuf[(__decodingRectWidth * outY) + outX] = p[0]; // Y
211                                                 outX++;
212                                         }
213                                         outY++;
214                                 }
215                         }
216                 }
217                 else // if not decoding a region
218                 {
219                         int row_stride = __pDec->output_width;
220                         buffSize = __pDec->output_width * __pDec->output_height * 3;
221                         length = buffSize;
222                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
223
224                         pReturnBuf = new (std::nothrow) byte[buffSize];
225                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
226                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
227
228                         // Initialize cb and cr to 128, since they need not be considered for gray scale image.
229                         memset(pReturnBuf, 128, buffSize);
230                         outBuf = pReturnBuf;
231
232                         while (__pDec->output_scanline < __pDec->output_height)
233                         {
234                                 jpeg_read_scanlines(__pDec, buffer, 1);
235
236                                 for (unsigned int x = 0; x < __pDec->output_width; x++)
237                                 {
238                                                 JSAMPLE* p = buffer[0] + x;
239                                         // YUV444  -> YUV444p
240                                         pReturnBuf[(__pDec->output_width * h) + x] = p[0]; // Y
241                                 }
242                                 h++;
243                         }
244                 }
245         }
246         else
247         {
248                 if (__isDecodeRegionEnabled == true)
249                 {
250                         buffSize = __decodingRectWidth * __decodingRectHeight * __pDec->output_components;
251                         planarSize = (__decodingRectWidth * __decodingRectHeight);
252                         length = buffSize;
253                         int row_stride = __pDec->output_width * __pDec->output_components;
254                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
255
256                         pReturnBuf = new (std::nothrow) byte[buffSize];
257                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
258                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
259
260                         memset(pReturnBuf, 0, buffSize);
261                         outBuf = pReturnBuf;
262
263                         while (__pDec->output_scanline < (__decodingRectY + __decodingRectHeight))
264                         {
265                                 jpeg_read_scanlines(__pDec, buffer, 1);
266                                 if (h >= __decodingRectY)
267                                 {
268                                         outX = 0;
269                                         for (int x = __decodingRectX; x < __decodingRectX + __decodingRectWidth; x++)
270                                         {
271                                                 JSAMPLE* p = buffer[0] + 3 * x;
272
273                                                 // YUV444  -> YUV444p
274                                                 pReturnBuf[(__decodingRectWidth * outY) + outX] = p[0];                                         // Y
275                                                 pReturnBuf[(__decodingRectWidth * outY) + planarSize + outX] = p[1];            // Cb
276                                                 pReturnBuf[(__decodingRectWidth * outY) + (planarSize * 2) + outX] = p[2];      // Cr
277                                                 outX++;
278                                         }
279                                         outY++;
280                                 }
281                                 h++;
282                         }
283                 }
284                 else
285                 {
286                         buffSize = __pDec->output_width * __pDec->output_height * __pDec->output_components;
287                         planarSize = __pDec->output_width * __pDec->output_height;
288                         length = buffSize;
289                         int row_stride = __pDec->output_width * __pDec->output_components;
290                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
291
292                         pReturnBuf = new (std::nothrow) byte[buffSize];
293                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
294                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
295
296                         memset(pReturnBuf, 0, buffSize);
297                         outBuf = pReturnBuf;
298
299                         while (__pDec->output_scanline < __pDec->output_height)
300                         {
301                                 jpeg_read_scanlines(__pDec, buffer, 1);
302
303                                 for (unsigned int x = 0; x < __pDec->output_width; x++)
304                                 {
305                                         JSAMPLE* p = buffer[0] + 3 * x;
306
307                                         // YUV444  -> YUV444p
308                                         pReturnBuf[(__pDec->output_width * h) + x] = p[0];                                              // Y
309                                         pReturnBuf[(__pDec->output_width * h) + planarSize + x] = p[1];                 // Cb
310                                         pReturnBuf[(__pDec->output_width * h) + (planarSize * 2) + x] = p[2];   // Cr
311                                 }
312                                 h++;
313                         }
314                 }
315         }
316
317         pReturnBuf = null;
318         SetLastResult(E_SUCCESS);
319 CATCH:
320         return outBuf;
321 }
322
323 result
324 _JpegDecoder::SetDecodingRegion(int x, int y, int width, int height)
325 {
326         SysTryReturnResult(NID_MEDIA, ((x >= 0) && (y >= 0) && ((x + width) <= __srcWidth) && ((y + height) <= __srcHeight)), E_INVALID_ARG,
327                         "Invalid Input - %d %d %d %d src_width - %d src_height - %d", x, y, width, height, __srcWidth, __srcHeight);
328         __decodingRectX = x;
329         __decodingRectY = y;
330         __decodingRectWidth = width;
331         __decodingRectHeight = height;
332         __isDecodeRegionEnabled = true;
333         return E_SUCCESS;
334 }
335
336 result
337 _JpegDecoder::GetDimension(int& width, int& height)
338 {
339         width = __srcWidth;
340         height = __srcHeight;
341
342         return E_SUCCESS;
343 }
344
345 MediaPixelFormat
346 _JpegDecoder::GetPixelFormat(void)
347 {
348         return MEDIA_PIXEL_FORMAT_YUV444P;
349 }
350
351 result
352 _JpegDecoder::SetScaleDown(int scaleDown)
353 {
354         __scale = scaleDown;
355         return E_SUCCESS;
356 }
357
358 result
359 _JpegDecoder::GetValue(const Tizen::Base::String& key, Tizen::Base::Object &value)
360 {
361         return E_UNSUPPORTED_OPERATION;
362 }
363
364 }} // Tizen::Media