Added bypass routine(JpegDecoder) when failed to get subsampling in JpegTurboDecoder
[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         // Set decoding option
163         if (__pDec->jpeg_color_space == JCS_GRAYSCALE)
164         {
165                 __pDec->out_color_space = JCS_GRAYSCALE;
166         }
167         else // YUV444
168         {
169                 __pDec->out_color_space = JCS_YCbCr;
170         }
171
172         // Start decompressor
173         jpeg_start_decompress(__pDec);
174
175         // Write output buffer
176         __srcWidth = __pDec->output_width;
177         __srcHeight = __pDec->output_height;
178
179         if (__pDec->output_components == 1)  // for grayscale
180         {
181                 if (__isDecodeRegionEnabled == true)
182                 {
183                         int row_stride = __pDec->output_width;
184                         buffSize = __decodingRectWidth * __decodingRectHeight * 3;
185                         length = buffSize;
186                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
187
188                         pReturnBuf = new (std::nothrow) byte[buffSize];
189                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
190                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
191
192                         // Initialize cb and cr to 128, since they need not be considered for gray scale image.
193                         memset(pReturnBuf, 128, buffSize);
194                         outBuf = pReturnBuf;
195
196                         while (__pDec->output_scanline < (__decodingRectY + __decodingRectHeight))
197                         {
198                                 jpeg_read_scanlines(__pDec, buffer, 1);
199                                 if (h >= __decodingRectY)
200                                 {
201                                         outX = 0;
202                                         for (int x = __decodingRectX; x < __decodingRectX + __decodingRectWidth; x++)
203                                         {
204                                                 JSAMPLE* p = buffer[0] + x;
205
206                                                 // YUV444  -> YUV444p
207                                                 pReturnBuf[(__decodingRectWidth * outY) + outX] = p[0]; // Y
208                                                 outX++;
209                                         }
210                                         outY++;
211                                 }
212                         }
213                 }
214                 else // if not decoding a region
215                 {
216                         int row_stride = __pDec->output_width;
217                         buffSize = __pDec->output_width * __pDec->output_height * 3;
218                         length = buffSize;
219                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
220
221                         pReturnBuf = new (std::nothrow) byte[buffSize];
222                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
223                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
224
225                         // Initialize cb and cr to 128, since they need not be considered for gray scale image.
226                         memset(pReturnBuf, 128, buffSize);
227                         outBuf = pReturnBuf;
228
229                         while (__pDec->output_scanline < __pDec->output_height)
230                         {
231                                 jpeg_read_scanlines(__pDec, buffer, 1);
232
233                                 for (unsigned int x = 0; x < __pDec->output_width; x++)
234                                 {
235                                                 JSAMPLE* p = buffer[0] + x;
236                                         // YUV444  -> YUV444p
237                                         pReturnBuf[(__pDec->output_width * h) + x] = p[0]; // Y
238                                 }
239                                 h++;
240                         }
241                 }
242         }
243         else
244         {
245                 if (__isDecodeRegionEnabled == true)
246                 {
247                         buffSize = __decodingRectWidth * __decodingRectHeight * __pDec->output_components;
248                         planarSize = (__decodingRectWidth * __decodingRectHeight);
249                         length = buffSize;
250                         int row_stride = __pDec->output_width * __pDec->output_components;
251                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
252
253                         pReturnBuf = new (std::nothrow) byte[buffSize];
254                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
255                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
256
257                         memset(pReturnBuf, 0, buffSize);
258                         outBuf = pReturnBuf;
259
260                         while (__pDec->output_scanline < (__decodingRectY + __decodingRectHeight))
261                         {
262                                 jpeg_read_scanlines(__pDec, buffer, 1);
263                                 if (h >= __decodingRectY)
264                                 {
265                                         outX = 0;
266                                         for (int x = __decodingRectX; x < __decodingRectX + __decodingRectWidth; x++)
267                                         {
268                                                 JSAMPLE* p = buffer[0] + 3 * x;
269
270                                                 // YUV444  -> YUV444p
271                                                 pReturnBuf[(__decodingRectWidth * outY) + outX] = p[0];                                         // Y
272                                                 pReturnBuf[(__decodingRectWidth * outY) + planarSize + outX] = p[1];            // Cb
273                                                 pReturnBuf[(__decodingRectWidth * outY) + (planarSize * 2) + outX] = p[2];      // Cr
274                                                 outX++;
275                                         }
276                                         outY++;
277                                 }
278                                 h++;
279                         }
280                 }
281                 else
282                 {
283                         buffSize = __pDec->output_width * __pDec->output_height * __pDec->output_components;
284                         planarSize = __pDec->output_width * __pDec->output_height;
285                         length = buffSize;
286                         int row_stride = __pDec->output_width * __pDec->output_components;
287                         JSAMPARRAY buffer = (*__pDec->mem->alloc_sarray)((struct jpeg_common_struct *) __pDec, JPOOL_IMAGE, row_stride, 1);
288
289                         pReturnBuf = new (std::nothrow) byte[buffSize];
290                         SysTryCatch(NID_MEDIA, pReturnBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
291                            "[E_OUT_OF_MEMORY] Could not allocate %d bytes for output.", buffSize);
292
293                         memset(pReturnBuf, 0, buffSize);
294                         outBuf = pReturnBuf;
295
296                         while (__pDec->output_scanline < __pDec->output_height)
297                         {
298                                 jpeg_read_scanlines(__pDec, buffer, 1);
299
300                                 for (unsigned int x = 0; x < __pDec->output_width; x++)
301                                 {
302                                         JSAMPLE* p = buffer[0] + 3 * x;
303
304                                         // YUV444  -> YUV444p
305                                         pReturnBuf[(__pDec->output_width * h) + x] = p[0];                                              // Y
306                                         pReturnBuf[(__pDec->output_width * h) + planarSize + x] = p[1];                 // Cb
307                                         pReturnBuf[(__pDec->output_width * h) + (planarSize * 2) + x] = p[2];   // Cr
308                                 }
309                                 h++;
310                         }
311                 }
312         }
313
314         pReturnBuf = null;
315         SetLastResult(E_SUCCESS);
316 CATCH:
317         return outBuf;
318 }
319
320 result
321 _JpegDecoder::SetDecodingRegion(int x, int y, int width, int height)
322 {
323         SysTryReturnResult(NID_MEDIA, ((x >= 0) && (y >= 0) && ((x + width) <= __srcWidth) && ((y + height) <= __srcHeight)), E_INVALID_ARG,
324                         "Invalid Input - %d %d %d %d src_width - %d src_height - %d", x, y, width, height, __srcWidth, __srcHeight);
325         __decodingRectX = x;
326         __decodingRectY = y;
327         __decodingRectWidth = width;
328         __decodingRectHeight = height;
329         __isDecodeRegionEnabled = true;
330         return E_SUCCESS;
331 }
332
333 result
334 _JpegDecoder::GetDimension(int& width, int& height)
335 {
336         width = __srcWidth;
337         height = __srcHeight;
338
339         return E_SUCCESS;
340 }
341
342 MediaPixelFormat
343 _JpegDecoder::GetPixelFormat(void)
344 {
345         return MEDIA_PIXEL_FORMAT_YUV444P;
346 }
347
348 result
349 _JpegDecoder::SetScaleDown(int scaleDown)
350 {
351         __scale = scaleDown;
352         return E_SUCCESS;
353 }
354
355 result
356 _JpegDecoder::GetValue(const Tizen::Base::String& key, Tizen::Base::Object &value)
357 {
358         return E_UNSUPPORTED_OPERATION;
359 }
360
361 }} // Tizen::Media