Arrange code
[apps/osp/Gallery.git] / src / GlThumbnailProvider.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 /**
18  * @file                GlThumbnailProvider.cpp
19  * @brief               This is the implementation file for ThumbnailProvider class.
20  */
21
22 #include <cstdlib>
23 #include <FContent.h>
24 #include <FMedia.h>
25 #include "GlResourceManager.h"
26 #include "GlThumbnailEvent.h"
27 #include "GlThumbnailEventArg.h"
28 #include "GlThumbnailJob.h"
29 #include "GlThumbnailProvider.h"
30 #include "GlTypes.h"
31
32 using namespace Tizen::Base;
33 using namespace Tizen::Base::Collection;
34 using namespace Tizen::Base::Runtime;
35 using namespace Tizen::Base::Utility;
36 using namespace Tizen::Content;
37 using namespace Tizen::Graphics;
38 using namespace Tizen::Media;
39
40 ThumbnailProvider* ThumbnailProvider::__pThumbnailProviderInstance = null;
41 ArrayList* ThumbnailProvider::__pThumbnailEventListener = null;
42
43 ThumbnailProvider::ThumbnailProvider(void)
44         : __pMutexCmd(null)
45         , __pCmdQueue(null)
46         , __requestId(0)
47         , __isAppTerminating(false)
48 {
49         AppLogDebug("ENTER");
50         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
51 }
52
53 ThumbnailProvider::~ThumbnailProvider(void)
54 {
55         AppLogDebug("ENTER");
56         if (__pThumbnailProviderInstance != null)
57         {
58                 __pThumbnailProviderInstance->Stop();
59                 __pThumbnailProviderInstance->Join();
60         }
61
62         if (__pThumbnailEventListener != null)
63         {
64                 delete __pThumbnailEventListener;
65         }
66
67         if (__pMutexCmd != null)
68         {
69                 delete __pMutexCmd;
70         }
71
72         if (__pCmdQueue != null)
73         {
74                 delete __pCmdQueue;
75         }
76         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
77 }
78
79 ThumbnailProvider*
80 ThumbnailProvider::GetInstance(void)
81 {
82         AppLogDebug("ENTER");
83         if (__pThumbnailProviderInstance == null)
84         {
85                 CreateInstance();
86                 __pThumbnailProviderInstance->Start();
87         }
88         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
89
90         return __pThumbnailProviderInstance;
91 }
92
93 result
94 ThumbnailProvider::Construct(void)
95 {
96         AppLogDebug("ENTER");
97
98         __pThumbnailEventListener = new (std::nothrow) ArrayList(SingleObjectDeleter);
99         result r = __pThumbnailEventListener->Construct();
100         TryCatch(r == E_SUCCESS,, "[%s] Unable to set event listener", GetErrorMessage(r));
101
102         __pMutexCmd = new (std::nothrow) Mutex();
103         r = __pMutexCmd->Create();
104         TryCatch(r == E_SUCCESS,, "[%s] Unable to create mutex", GetErrorMessage(r));
105
106         if (__pCmdQueue != null)
107         {
108                 delete __pCmdQueue;
109         }
110         __pCmdQueue = new (std::nothrow) ArrayList(SingleObjectDeleter);
111         r = __pCmdQueue->Construct();
112         TryCatch(r == E_SUCCESS,, "[%s] Unable to construct queue", GetErrorMessage(r));
113         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
114
115         return EventDrivenThread::Construct();
116
117 CATCH:
118         if (__pThumbnailEventListener != null)
119         {
120                 delete __pThumbnailEventListener;
121                 __pThumbnailEventListener = null;
122         }
123
124         if (__pMutexCmd != null)
125         {
126                 delete __pMutexCmd;
127                 __pMutexCmd = null;
128         }
129
130         if (__pCmdQueue != null)
131         {
132                 delete __pCmdQueue;
133                 __pCmdQueue = null;
134         }
135         AppLogDebug("EXIT with exception(%s)", GetErrorMessage(GetLastResult()));
136
137         return E_FAILURE;
138 }
139
140 void
141 ThumbnailProvider::CreateInstance(void)
142 {
143         AppLogDebug("ENTER");
144         __pThumbnailProviderInstance = new (std::nothrow) ThumbnailProvider();
145         result r = __pThumbnailProviderInstance->Construct();
146
147         if (IsFailed(r) == true)
148         {
149                 delete __pThumbnailProviderInstance;
150                 __pThumbnailProviderInstance = null;
151                 AppLogDebug("EXIT 1(%s)", GetErrorMessage(GetLastResult()));
152
153                 return;
154         }
155
156         std::atexit(DestroyInstance);
157         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
158 }
159
160 void
161 ThumbnailProvider::DestroyInstance(void)
162 {
163         AppLogDebug("ENTER");
164         delete __pThumbnailProviderInstance;
165         __pThumbnailProviderInstance = null;
166         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
167 }
168
169 void
170 ThumbnailProvider::Release(void)
171 {
172         AppLogDebug("ENTER");
173         if (__pThumbnailProviderInstance != null)
174         {
175                 delete __pThumbnailProviderInstance;
176                 __pThumbnailProviderInstance = null;
177         }
178         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
179 }
180
181 void
182 ThumbnailProvider::RequestThumbnail(const ContentId& contentId, const ThumbnailEvent* event)
183 {
184         AppLogDebug("ENTER");
185         AppLogDebug("[THREAD] Request Job - (MainThread)");
186
187         if (contentId.ToString().IsEmpty() == true || event == null
188                                 || __pMutexCmd == null || __pCmdQueue == null)
189         {
190                 AppLogDebug("EXIT 1(%s)", GetErrorMessage(GetLastResult()));
191                 return;
192         }
193
194         __pMutexCmd->Acquire();
195
196         ThumbnailJob* pThumbnailJob = new (std::nothrow) ThumbnailJob();
197         pThumbnailJob->Construct(contentId, ++__requestId, event);
198         __pCmdQueue->Add(pThumbnailJob);
199
200         __pMutexCmd->Release();
201
202         SendUserEvent(null, null);
203         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
204 }
205
206 void
207 ThumbnailProvider::ClearThumbnailRequests(const bool appTerminating)
208 {
209         AppLogDebug("ENTER");
210         if (__pMutexCmd != null)
211         {
212                 __pMutexCmd->Acquire();
213                 if (__pCmdQueue != null && __pCmdQueue->GetCount() > 0)
214                 {
215                         __pCmdQueue->RemoveAll(true);
216                 }
217
218                 if (appTerminating == true)
219                 {
220                         __isAppTerminating = true;
221                 }
222                 __pMutexCmd->Release();
223         }
224         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
225 }
226
227 bool
228 ThumbnailProvider::OnStart(void)
229 {
230         AppLogDebug("ENTER");
231         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
232
233         return true;
234 }
235
236 void
237 ThumbnailProvider::OnStop(void)
238 {
239         AppLogDebug("ENTER");
240         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
241 }
242
243 void
244 ThumbnailProvider::OnUserEventReceivedN(RequestId requestId, IList* pArgs)
245 {
246         AppLogDebug("ENTER");
247         AppLogDebug("[THREAD] Receive Job Message - (SubThread)");
248         ThumbnailJob* pThumbnailJob = null;
249         ThumbnailInfo* pThumbnailInfo = null;
250         ContentId contentId;
251
252         if (__pMutexCmd == null || __pCmdQueue == null)
253         {
254                 delete pArgs;
255                 AppLogDebug("EXIT1(%s)", GetErrorMessage(GetLastResult()));
256                 return;
257         }
258
259         __pMutexCmd->Acquire();
260         if (__pCmdQueue->GetCount() > 0)
261         {
262                 pThumbnailJob = static_cast<ThumbnailJob*>(__pCmdQueue->GetAt(0));
263                 if (pThumbnailJob == null)
264                 {
265                         __pCmdQueue->RemoveAt(0);
266                         __pMutexCmd->Release();
267                         return;
268                 }
269
270                 unsigned long requestId = pThumbnailJob->GetRequestId();
271                 ContentId contentId = pThumbnailJob->GetContentId();
272                 __pMutexCmd->Release();
273
274                 pThumbnailInfo = GetThumbnailInfoN(contentId);
275
276                 __pMutexCmd->Acquire();
277                 pThumbnailJob = static_cast<ThumbnailJob*>(__pCmdQueue->GetAt(0));
278
279                 if (pThumbnailJob != null && pThumbnailInfo != null && requestId == pThumbnailJob->GetRequestId())
280                 {
281                         ContentType contentType = pThumbnailInfo->GetContentType();
282                         if (contentType == CONTENT_TYPE_IMAGE || contentType == CONTENT_TYPE_VIDEO)
283                         {
284                                 ThumbnailEvent* pThumbnailEvent = const_cast<ThumbnailEvent*>(pThumbnailJob->GetEvent());
285                                 if (pThumbnailEvent != null)
286                                 {
287                                         if (__isAppTerminating != true)
288                                         {
289                                                 ThumbnailEventArg* pSendingArg = new (std::nothrow)ThumbnailEventArg(pThumbnailInfo);
290                                                 pThumbnailEvent->Fire(*pSendingArg);
291                                         }
292                                 }
293                         }
294                         else
295                         {
296                                 delete pThumbnailInfo;
297                         }
298                         __pCmdQueue->RemoveAt(0, true);
299                 }
300                 else
301                 {
302                         delete pThumbnailInfo;
303                 }
304         }
305         __pMutexCmd->Release();
306
307         delete pArgs;
308
309         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
310 }
311
312 ThumbnailInfo*
313 ThumbnailProvider::GetThumbnailInfoN(const ContentId& contentId) const
314 {
315         AppLogDebug("ENTER");
316         ThumbnailInfo* pNewThumbnailInfo = null;
317
318         ContentManager contentManager;
319         result r = contentManager.Construct();
320         if (r == E_SUCCESS)
321         {
322                 Bitmap* pBitmap = null;
323                 long duration = 0;
324
325                 ContentInfo* pContentInfo = contentManager.GetContentInfoN(contentId);
326
327                 if (pContentInfo != null)
328                 {
329                         String path = pContentInfo->GetContentPath();
330                         if (path.EndsWith(L"tif") != true
331                                 && path.EndsWith(L"tiff") != true
332                                 && path.EndsWith(L"wbmp") != true
333                                 && path.EndsWith(L"TIF") != true
334                                 && path.EndsWith(L"TIFF") != true
335                                 && path.EndsWith(L"WBMP") != true)
336                         {
337                                 pBitmap = pContentInfo->GetThumbnailN();
338                         }
339
340                         if (pBitmap == null)
341                         {
342                                 pBitmap = GetThumbnailByDecodeN(pContentInfo->GetContentPath(), pContentInfo->GetContentType());
343                                 if (pBitmap == null)
344                                 {
345                                         pBitmap = ResourceManager::GetBitmapN(IDB_NO_CONTENTS_BROKEN);
346                                 }
347                         }
348                         pBitmap->Scale(DIMENSION_DEFAULT_THUMBNAIL);
349
350                         ContentType contentType = pContentInfo->GetContentType();
351
352                         if (contentType == CONTENT_TYPE_VIDEO)
353                         {
354                                 VideoContentInfo* pVideoContentInfo = static_cast<VideoContentInfo*>(pContentInfo);
355                                 duration = pVideoContentInfo->GetDuration();
356                         }
357
358                         pNewThumbnailInfo = new (std::nothrow) ThumbnailInfo();
359                         pNewThumbnailInfo->Construct(contentId, pContentInfo->GetContentPath(), *pBitmap, contentType, duration);
360                         delete pBitmap;
361                         delete pContentInfo;
362                 }
363         }
364         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
365
366         return pNewThumbnailInfo;
367 }
368
369 Bitmap*
370 ThumbnailProvider::GetThumbnailByDecodeN(const String& filePath, const ContentType contentType) const
371 {
372         AppLogDebug("ENTER");
373         Bitmap* pBitmap = null;
374         if (&filePath == null || filePath.GetLength() <= 0)
375         {
376                 pBitmap = new (std::nothrow) Bitmap();
377                 pBitmap->Construct(DIMENSION_DEFAULT_THUMBNAIL, BITMAP_PIXEL_FORMAT_RGB565);
378         }
379         else
380         {
381                 if (contentType == CONTENT_TYPE_IMAGE)
382                 {
383                         ImageBuffer pImageBuffer;
384                         result r = pImageBuffer.Construct(filePath);
385                         if (r == E_SUCCESS)
386                         {
387                                 pBitmap = pImageBuffer.GetBitmapN(BITMAP_PIXEL_FORMAT_ARGB8888, BUFFER_SCALING_AUTO);
388                         }
389                 }
390                 else if (contentType == CONTENT_TYPE_VIDEO)
391                 {
392                         VideoFrameExtractor extractor;
393                         result r = extractor.Construct(filePath, MEDIA_PIXEL_FORMAT_RGB565LE);
394                         if (r == E_SUCCESS)
395                         {
396                                 ImageBuffer* pImageBuffer = extractor.GetFrameN(0);
397                                 if (pImageBuffer != null)
398                                 {
399                                         pBitmap = pImageBuffer->GetBitmapN(BITMAP_PIXEL_FORMAT_RGB565, BUFFER_SCALING_AUTO);
400                                         delete pImageBuffer;
401                                 }
402                         }
403                 }
404         }
405         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
406
407         return pBitmap;
408 }
409
410 String
411 ThumbnailProvider::GetFileNameFromFullPath(const String& fullPath, bool withExt) const
412 {
413         AppLogDebug("ENTER");
414         if (fullPath.CompareTo(EMPTY_SPACE) == 0)
415         {
416                 AppLogDebug("EXIT 1(%s)", GetErrorMessage(GetLastResult()));
417
418                 return EMPTY_SPACE;
419         }
420
421         String delim(DIRECTORY_SEPARATOR);
422         StringTokenizer st(fullPath,delim);
423         String token;
424         while (st.HasMoreTokens())
425         {
426                 st.GetNextToken(token);
427         }
428
429         if (withExt == true)
430         {
431                 AppLogDebug("EXIT 2(%s)", GetErrorMessage(GetLastResult()));
432
433                 return token;
434         }
435         else
436         {
437                 String subDelim(FILE_EXT_SEPARATOR);
438                 StringTokenizer subSt(token, subDelim);
439                 String subToken;
440                 subSt.GetNextToken(subToken);
441                 AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
442
443                 return subToken;
444         }
445 }