810553aca2774d9016abba7622289d009cb459ba
[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.0 (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         , __appTerminating(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::CancelThumbnailRequest(const ContentId& contentId, const ThumbnailEvent* event)
208 {
209         AppLogDebug("ENTER");
210         ThumbnailJob* pThumbnailJob = null;
211
212         if (__pMutexCmd == null || __pCmdQueue == null)
213         {
214                 AppLogDebug("EXIT 1(%s)", GetErrorMessage(GetLastResult()));
215                 return;
216         }
217
218         __pMutexCmd->Acquire();
219
220         int loopCount = __pCmdQueue->GetCount();
221         for (int i = 0; i < loopCount; ++i)
222         {
223                 pThumbnailJob = static_cast<ThumbnailJob*>(__pCmdQueue->GetAt(i));
224
225                 if (pThumbnailJob != null
226                         && pThumbnailJob->GetContentId() == contentId
227                         && pThumbnailJob->GetEvent() == event)
228                 {
229                         AppLogDebug("ENTER i(%d) event(%x)", i, event);
230                         __pCmdQueue->RemoveAt(i, true);
231                         break;
232                 }
233         }
234         __pMutexCmd->Release();
235         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
236 }
237
238 void
239 ThumbnailProvider::ClearThumbnailRequests(bool appTerminating)
240 {
241         AppLogDebug("ENTER");
242         if (__pMutexCmd != null)
243         {
244                 __pMutexCmd->Acquire();
245                 if (__pCmdQueue != null && __pCmdQueue->GetCount() > 0)
246                 {
247                         __pCmdQueue->RemoveAll(true);
248                 }
249
250                 if (appTerminating == true)
251                 {
252                         __appTerminating = true;
253                 }
254                 __pMutexCmd->Release();
255         }
256         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
257 }
258
259 bool
260 ThumbnailProvider::OnStart(void)
261 {
262         AppLogDebug("ENTER");
263         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
264
265         return true;
266 }
267
268 void
269 ThumbnailProvider::OnStop(void)
270 {
271         AppLogDebug("ENTER");
272         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
273 }
274
275 void
276 ThumbnailProvider::OnUserEventReceivedN(RequestId requestId, IList* pArgs)
277 {
278         AppLogDebug("ENTER");
279         AppLogDebug("[THREAD] Receive Job Message - (SubThread)");
280         ThumbnailJob* pThumbnailJob = null;
281         ThumbnailInfo* pThumbnailInfo = null;
282         ContentId contentId;
283
284         if (__pMutexCmd == null || __pCmdQueue == null)
285         {
286                 delete pArgs;
287                 AppLogDebug("EXIT1(%s)", GetErrorMessage(GetLastResult()));
288                 return;
289         }
290
291         __pMutexCmd->Acquire();
292         if (__pCmdQueue->GetCount() > 0)
293         {
294                 pThumbnailJob = static_cast<ThumbnailJob*>(__pCmdQueue->GetAt(0));
295                 if (pThumbnailJob == null)
296                 {
297                         __pCmdQueue->RemoveAt(0);
298                         __pMutexCmd->Release();
299                         return;
300                 }
301
302                 unsigned long requestId = pThumbnailJob->GetRequestId();
303                 ContentId contentId = pThumbnailJob->GetContentId();
304                 __pMutexCmd->Release();
305
306                 pThumbnailInfo = GetThumbnailInfoN(contentId);
307
308                 __pMutexCmd->Acquire();
309                 pThumbnailJob = static_cast<ThumbnailJob*>(__pCmdQueue->GetAt(0));
310
311                 if (pThumbnailJob != null && pThumbnailInfo != null && requestId == pThumbnailJob->GetRequestId())
312                 {
313                         ContentType contentType = pThumbnailInfo->GetContentType();
314                         if (contentType == CONTENT_TYPE_IMAGE || contentType == CONTENT_TYPE_VIDEO)
315                         {
316                                 ThumbnailEvent* pThumbnailEvent = const_cast<ThumbnailEvent*>(pThumbnailJob->GetEvent());
317                                 if (pThumbnailEvent != null)
318                                 {
319                                         if (__appTerminating != true)
320                                         {
321                                                 ThumbnailEventArg* pSendingArg = new (std::nothrow)ThumbnailEventArg(pThumbnailInfo);
322                                                 pThumbnailEvent->Fire(*pSendingArg);
323                                         }
324                                 }
325                         }
326                         else
327                         {
328                                 delete pThumbnailInfo;
329                         }
330                         __pCmdQueue->RemoveAt(0, true);
331                 }
332                 else
333                 {
334                         delete pThumbnailInfo;
335                 }
336         }
337         __pMutexCmd->Release();
338
339         delete pArgs;
340
341         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
342 }
343
344 ThumbnailInfo*
345 ThumbnailProvider::GetThumbnailInfoN(const ContentId& contentId) const
346 {
347         AppLogDebug("ENTER");
348         ThumbnailInfo* pNewThumbnailInfo = null;
349
350         ContentManager contentManager;
351         result r = contentManager.Construct();
352         if (r == E_SUCCESS)
353         {
354                 Bitmap* pBitmap = null;
355                 long duration = 0;
356
357                 ContentInfo* pContentInfo = contentManager.GetContentInfoN(contentId);
358
359                 if (pContentInfo != null)
360                 {
361                         pBitmap = pContentInfo->GetThumbnailN();
362
363                         if (pBitmap == null)
364                         {
365                                 pBitmap = GetThumbnailByDecodeN(pContentInfo->GetContentPath(), pContentInfo->GetContentType());
366                                 if (pBitmap == null)
367                                 {
368                                         pBitmap = ResourceManager::GetBitmapN(IDB_NO_CONTENTS_BROKEN);
369                                 }
370                         }
371                         pBitmap->Scale(DIMENSION_DEFAULT_THUMBNAIL);
372                 }
373                 else
374                 {
375                         delete pContentInfo;
376                         AppLogDebug("EXIT 2(%s)", GetErrorMessage(GetLastResult()));
377
378                         return null;
379                 }
380
381                 ContentType contentType = pContentInfo->GetContentType();
382                 if (contentType == CONTENT_TYPE_VIDEO)
383                 {
384                         VideoContentInfo* pVideoContentInfo = static_cast<VideoContentInfo*>(pContentInfo);
385                         duration = pVideoContentInfo->GetDuration();
386                 }
387                 pNewThumbnailInfo = new (std::nothrow) ThumbnailInfo();
388                 pNewThumbnailInfo->Construct(contentId, pContentInfo->GetContentPath(), *pBitmap, contentType, duration);
389                 delete pBitmap;
390         }
391         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
392
393         return pNewThumbnailInfo;
394 }
395
396 Bitmap*
397 ThumbnailProvider::GetThumbnailByDecodeN(const String& filePath, const ContentType contentType) const
398 {
399         AppLogDebug("ENTER");
400         Bitmap* pBitmap = null;
401         if (&filePath == null || filePath.GetLength() <= 0)
402         {
403                 pBitmap = new (std::nothrow) Bitmap();
404                 pBitmap->Construct(DIMENSION_DEFAULT_THUMBNAIL, BITMAP_PIXEL_FORMAT_RGB565);
405         }
406         else
407         {
408                 if (contentType == CONTENT_TYPE_IMAGE)
409                 {
410                         ImageBuffer pImageBuffer;
411                         result r = pImageBuffer.Construct(filePath);
412                         if (r == E_SUCCESS)
413                         {
414                                 pBitmap = pImageBuffer.GetBitmapN(BITMAP_PIXEL_FORMAT_ARGB8888, BUFFER_SCALING_AUTO);
415                         }
416                 }
417                 else if (contentType == CONTENT_TYPE_VIDEO)
418                 {
419                         VideoFrameExtractor extractor;
420                         result r = extractor.Construct(filePath, MEDIA_PIXEL_FORMAT_RGB565LE);
421                         if (r == E_SUCCESS)
422                         {
423                                 ImageBuffer* pImageBuffer = extractor.GetFrameN(0);
424                                 if (pImageBuffer != null)
425                                 {
426                                         pBitmap = pImageBuffer->GetBitmapN(BITMAP_PIXEL_FORMAT_RGB565, BUFFER_SCALING_AUTO);
427                                         delete pImageBuffer;
428                                 }
429                         }
430                 }
431         }
432         AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
433
434         return pBitmap;
435 }
436
437 String
438 ThumbnailProvider::GetFileNameFromFullPath(const String& fullPath, bool withExt) const
439 {
440         AppLogDebug("ENTER");
441         if (fullPath.CompareTo(EMPTY_SPACE) == 0)
442         {
443                 AppLogDebug("EXIT 1(%s)", GetErrorMessage(GetLastResult()));
444
445                 return EMPTY_SPACE;
446         }
447
448         String delim(DIRECTORY_SEPARATOR);
449         StringTokenizer st(fullPath,delim);
450         String token;
451         while (st.HasMoreTokens())
452         {
453                 st.GetNextToken(token);
454         }
455
456         if (withExt == true)
457         {
458                 AppLogDebug("EXIT 2(%s)", GetErrorMessage(GetLastResult()));
459
460                 return token;
461         }
462         else
463         {
464                 String subDelim(FILE_EXT_SEPARATOR);
465                 StringTokenizer subSt(token, subDelim);
466                 String subToken;
467                 subSt.GetNextToken(subToken);
468                 AppLogDebug("EXIT(%s)", GetErrorMessage(GetLastResult()));
469
470                 return subToken;
471         }
472 }