(WebP Loader) Ensure member variables are initialised (SVACE issue)
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / webp-loading.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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 // CLASS HEADER
19 #include <dali/internal/imaging/common/webp-loading.h>
20
21 // EXTERNAL INCLUDES
22 #ifdef DALI_WEBP_AVAILABLE
23 #include <webp/decode.h>
24 #include <webp/demux.h>
25
26 #if WEBP_DEMUX_ABI_VERSION > 0x0101
27 #define DALI_WEBP_ENABLED 1
28 #endif
29
30 #endif
31 #include <dali/integration-api/debug.h>
32 #include <dali/public-api/images/pixel-data.h>
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <cstring>
39 #include <dali/internal/imaging/common/file-download.h>
40 #include <dali/internal/system/common/file-reader.h>
41
42 typedef unsigned char WebPByteType;
43
44 namespace Dali
45 {
46
47 namespace Internal
48 {
49
50 namespace Adaptor
51 {
52
53 namespace
54 {
55
56 #if defined(DEBUG_ENABLED)
57 Debug::Filter *gWebPLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
58 #endif
59
60 constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024;
61
62 }
63
64 struct WebPLoading::Impl
65 {
66 public:
67   Impl( const std::string& url, bool isLocalResource )
68   : mUrl( url )
69   {
70 #ifdef DALI_WEBP_ENABLED
71     if( ReadWebPInformation( isLocalResource ) )
72     {
73       WebPAnimDecoderOptions webPAnimDecoderOptions;
74       WebPAnimDecoderOptionsInit( &webPAnimDecoderOptions );
75       webPAnimDecoderOptions.color_mode = MODE_RGBA;
76       mWebPAnimDecoder = WebPAnimDecoderNew( &mWebPData, &webPAnimDecoderOptions );
77       WebPAnimDecoderGetInfo( mWebPAnimDecoder, &mWebPAnimInfo );
78       mTimeStamp.assign( mWebPAnimInfo.frame_count, 0 );
79     }
80 #endif
81   }
82
83   bool ReadWebPInformation( bool isLocalResource )
84   {
85 #ifdef DALI_WEBP_ENABLED
86     WebPDataInit( &mWebPData );
87     if( isLocalResource )
88     {
89       Internal::Platform::FileReader fileReader( mUrl );
90       FILE *fp = fileReader.GetFile();
91       if( fp == NULL )
92       {
93         return false;
94       }
95
96       if( fseek( fp, 0, SEEK_END ) <= -1 )
97       {
98         return false;
99       }
100
101       mWebPData.size = ftell( fp );
102       if( ( ! fseek( fp, 0, SEEK_SET ) ) )
103       {
104         unsigned char *WebPDataBuffer;
105         WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * mWebPData.size ) );
106         mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
107         mWebPData.bytes = WebPDataBuffer;
108       }
109       else
110       {
111         return false;
112       }
113     }
114     else
115     {
116       // remote file
117       bool succeeded;
118       Dali::Vector<uint8_t> dataBuffer;
119       size_t dataSize;
120
121       succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
122       if( succeeded )
123       {
124         size_t blobSize = dataBuffer.Size();
125         if( blobSize > 0U )
126         {
127           // Open a file handle on the memory buffer:
128           Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
129           FILE * const fp = fileReader.GetFile();
130           if ( NULL != fp )
131           {
132             if( ( ! fseek( fp, 0, SEEK_SET ) ) )
133             {
134               unsigned char *WebPDataBuffer;
135               WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * blobSize ) );
136               mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
137               mWebPData.bytes = WebPDataBuffer;
138             }
139             else
140             {
141               DALI_LOG_ERROR( "Error seeking within file\n" );
142             }
143           }
144           else
145           {
146             DALI_LOG_ERROR( "Error reading file\n" );
147           }
148         }
149       }
150     }
151     return true;
152 #else
153     return false;
154 #endif
155   }
156
157   // Moveable but not copyable
158
159   Impl( const Impl& ) = delete;
160   Impl& operator=( const Impl& ) = delete;
161   Impl( Impl&& ) = default;
162   Impl& operator=( Impl&& ) = default;
163
164   ~Impl()
165   {
166 #ifdef DALI_WEBP_ENABLED
167     if( &mWebPData != NULL )
168     {
169       free( (void*)mWebPData.bytes );
170       mWebPData.bytes = nullptr;
171       WebPDataInit( &mWebPData );
172     }
173     if( mWebPAnimDecoder )
174     {
175       WebPAnimDecoderDelete(mWebPAnimDecoder);
176     }
177 #endif
178   }
179
180   std::string mUrl;
181   std::vector<uint32_t> mTimeStamp;
182   uint32_t mLoadingFrame{0};
183
184 #ifdef DALI_WEBP_ENABLED
185   WebPData mWebPData{0};
186   WebPAnimDecoder* mWebPAnimDecoder{nullptr};
187   WebPAnimInfo mWebPAnimInfo{0};
188 #endif
189 };
190
191 AnimatedImageLoadingPtr WebPLoading::New( const std::string &url, bool isLocalResource )
192 {
193 #ifndef DALI_WEBP_ENABLED
194   DALI_LOG_ERROR( "The system does not support Animated WebP format.\n" );
195 #endif
196   return AnimatedImageLoadingPtr( new WebPLoading( url, isLocalResource ) );
197 }
198
199 WebPLoading::WebPLoading( const std::string &url, bool isLocalResource )
200 : mImpl( new WebPLoading::Impl( url, isLocalResource ) )
201 {
202 }
203
204 WebPLoading::~WebPLoading()
205 {
206   delete mImpl;
207 }
208
209 bool WebPLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
210 {
211 #ifdef DALI_WEBP_ENABLED
212   if( frameStartIndex  >= mImpl->mWebPAnimInfo.frame_count )
213   {
214     return false;
215   }
216
217   DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count );
218
219   if( mImpl->mLoadingFrame > frameStartIndex  )
220   {
221     mImpl->mLoadingFrame = 0;
222     WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
223   }
224
225   for( ; mImpl->mLoadingFrame < frameStartIndex ; ++mImpl->mLoadingFrame )
226   {
227     uint8_t* frameBuffer;
228     int timestamp;
229     WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
230     mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
231   }
232
233   for( int i = 0; i < count; ++i )
234   {
235     const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
236     uint8_t* frameBuffer;
237     int timestamp;
238     WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
239
240     auto pixelBuffer = new uint8_t[ bufferSize ];
241     memcpy( pixelBuffer, frameBuffer, bufferSize );
242     mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
243
244     if( pixelBuffer )
245     {
246       pixelData.push_back( Dali::PixelData::New( pixelBuffer, bufferSize,
247                                                  mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height,
248                                                  Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY) );
249     }
250
251     mImpl->mLoadingFrame++;
252     if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
253     {
254       mImpl->mLoadingFrame = 0;
255       WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
256     }
257   }
258
259   return true;
260 #else
261   return false;
262 #endif
263 }
264
265 Dali::Devel::PixelBuffer WebPLoading::LoadFrame( uint32_t frameIndex )
266 {
267   Dali::Devel::PixelBuffer pixelBuffer;
268 #ifdef DALI_WEBP_ENABLED
269   if( frameIndex  >= mImpl->mWebPAnimInfo.frame_count )
270   {
271     return pixelBuffer;
272   }
273
274   DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameIndex:%d )\n", frameIndex );
275
276   if( mImpl->mLoadingFrame > frameIndex  )
277   {
278     mImpl->mLoadingFrame = 0;
279     WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
280   }
281
282   for( ; mImpl->mLoadingFrame < frameIndex ; ++mImpl->mLoadingFrame )
283   {
284     uint8_t* frameBuffer;
285     int timestamp;
286     WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
287     mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
288   }
289
290   const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
291   uint8_t* frameBuffer;
292   int timestamp;
293   WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, &timestamp );
294
295   pixelBuffer = Dali::Devel::PixelBuffer::New( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888 );
296   memcpy( pixelBuffer.GetBuffer(), frameBuffer, bufferSize );
297   mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
298
299   mImpl->mLoadingFrame++;
300   if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
301   {
302     mImpl->mLoadingFrame = 0;
303     WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
304   }
305 #endif
306   return pixelBuffer;
307 }
308
309 ImageDimensions WebPLoading::GetImageSize() const
310 {
311 #ifdef DALI_WEBP_ENABLED
312   return ImageDimensions( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height );
313 #else
314   return ImageDimensions();
315 #endif
316 }
317
318 uint32_t WebPLoading::GetImageCount() const
319 {
320 #ifdef DALI_WEBP_ENABLED
321   return mImpl->mWebPAnimInfo.frame_count;
322 #else
323   return 0u;
324 #endif
325 }
326
327 uint32_t WebPLoading::GetFrameInterval( uint32_t frameIndex ) const
328 {
329   if( frameIndex >= GetImageCount() )
330   {
331     return 0u;
332   }
333   else
334   {
335     if( frameIndex > 0 )
336     {
337       return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
338     }
339     return mImpl->mTimeStamp[frameIndex];
340   }
341 }
342
343 std::string WebPLoading::GetUrl() const
344 {
345   return mImpl->mUrl;
346 }
347
348 } // namespace Adaptor
349
350 } // namespace Internal
351
352 } // namespace Dali