2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/imaging/common/webp-loading.h>
22 #ifdef DALI_WEBP_AVAILABLE
23 #include <webp/decode.h>
24 #include <webp/demux.h>
26 #if WEBP_DEMUX_ABI_VERSION > 0x0101
27 #define DALI_WEBP_ENABLED 1
31 #include <dali/integration-api/debug.h>
32 #include <dali/public-api/images/pixel-data.h>
34 #include <sys/types.h>
39 #include <dali/internal/imaging/common/file-download.h>
40 #include <dali/internal/system/common/file-reader.h>
41 #include <dali/devel-api/threading/mutex.h>
43 typedef unsigned char WebPByteType;
57 #if defined(DEBUG_ENABLED)
58 Debug::Filter *gWebPLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
61 constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
65 struct WebPLoading::Impl
68 Impl( const std::string& url, bool isLocalResource )
72 #ifdef DALI_WEBP_ENABLED
73 if( ReadWebPInformation( isLocalResource ) )
75 WebPAnimDecoderOptions webPAnimDecoderOptions;
76 WebPAnimDecoderOptionsInit( &webPAnimDecoderOptions );
77 webPAnimDecoderOptions.color_mode = MODE_RGBA;
78 mWebPAnimDecoder = WebPAnimDecoderNew( &mWebPData, &webPAnimDecoderOptions );
79 WebPAnimDecoderGetInfo( mWebPAnimDecoder, &mWebPAnimInfo );
80 mTimeStamp.assign( mWebPAnimInfo.frame_count, 0 );
85 bool ReadWebPInformation( bool isLocalResource )
87 #ifdef DALI_WEBP_ENABLED
88 WebPDataInit( &mWebPData );
91 Internal::Platform::FileReader fileReader( mUrl );
92 FILE *fp = fileReader.GetFile();
98 if( fseek( fp, 0, SEEK_END ) <= -1 )
103 mWebPData.size = ftell( fp );
104 if( ( ! fseek( fp, 0, SEEK_SET ) ) )
106 unsigned char *WebPDataBuffer;
107 WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * mWebPData.size ) );
108 mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
109 mWebPData.bytes = WebPDataBuffer;
120 Dali::Vector<uint8_t> dataBuffer;
123 succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
126 size_t blobSize = dataBuffer.Size();
129 // Open a file handle on the memory buffer:
130 Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
131 FILE * const fp = fileReader.GetFile();
134 if( ( ! fseek( fp, 0, SEEK_SET ) ) )
136 unsigned char *WebPDataBuffer;
137 WebPDataBuffer = reinterpret_cast<WebPByteType*>( malloc(sizeof( WebPByteType ) * blobSize ) );
138 mWebPData.size = fread( WebPDataBuffer, sizeof( WebPByteType ), mWebPData.size, fp );
139 mWebPData.bytes = WebPDataBuffer;
143 DALI_LOG_ERROR( "Error seeking within file\n" );
148 DALI_LOG_ERROR( "Error reading file\n" );
159 // Moveable but not copyable
161 Impl( const Impl& ) = delete;
162 Impl& operator=( const Impl& ) = delete;
163 Impl( Impl&& ) = default;
164 Impl& operator=( Impl&& ) = default;
168 #ifdef DALI_WEBP_ENABLED
169 if( &mWebPData != NULL )
171 free( (void*)mWebPData.bytes );
172 mWebPData.bytes = nullptr;
173 WebPDataInit( &mWebPData );
175 if( mWebPAnimDecoder )
177 WebPAnimDecoderDelete(mWebPAnimDecoder);
183 std::vector<uint32_t> mTimeStamp;
184 uint32_t mLoadingFrame{0};
187 #ifdef DALI_WEBP_ENABLED
188 WebPData mWebPData{0};
189 WebPAnimDecoder* mWebPAnimDecoder{nullptr};
190 WebPAnimInfo mWebPAnimInfo{0};
194 AnimatedImageLoadingPtr WebPLoading::New( const std::string &url, bool isLocalResource )
196 #ifndef DALI_WEBP_ENABLED
197 DALI_LOG_ERROR( "The system does not support Animated WebP format.\n" );
199 return AnimatedImageLoadingPtr( new WebPLoading( url, isLocalResource ) );
202 WebPLoading::WebPLoading( const std::string &url, bool isLocalResource )
203 : mImpl( new WebPLoading::Impl( url, isLocalResource ) )
207 WebPLoading::~WebPLoading()
212 bool WebPLoading::LoadNextNFrames( uint32_t frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
214 #ifdef DALI_WEBP_ENABLED
215 Mutex::ScopedLock lock( mImpl->mMutex );
216 if( frameStartIndex >= mImpl->mWebPAnimInfo.frame_count )
221 DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count );
223 if( mImpl->mLoadingFrame > frameStartIndex )
225 mImpl->mLoadingFrame = 0;
226 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
229 for( ; mImpl->mLoadingFrame < frameStartIndex ; ++mImpl->mLoadingFrame )
231 uint8_t* frameBuffer;
233 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
234 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
237 for( int i = 0; i < count; ++i )
239 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
240 uint8_t* frameBuffer;
242 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
244 auto pixelBuffer = new uint8_t[ bufferSize ];
245 memcpy( pixelBuffer, frameBuffer, bufferSize );
246 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
250 pixelData.push_back( Dali::PixelData::New( pixelBuffer, bufferSize,
251 mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height,
252 Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY) );
255 mImpl->mLoadingFrame++;
256 if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
258 mImpl->mLoadingFrame = 0;
259 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
269 Dali::Devel::PixelBuffer WebPLoading::LoadFrame( uint32_t frameIndex )
271 Dali::Devel::PixelBuffer pixelBuffer;
272 #ifdef DALI_WEBP_ENABLED
273 Mutex::ScopedLock lock( mImpl->mMutex );
274 if( frameIndex >= mImpl->mWebPAnimInfo.frame_count )
279 DALI_LOG_INFO( gWebPLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameIndex:%d )\n", frameIndex );
281 if( mImpl->mLoadingFrame > frameIndex )
283 mImpl->mLoadingFrame = 0;
284 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
287 for( ; mImpl->mLoadingFrame < frameIndex ; ++mImpl->mLoadingFrame )
289 uint8_t* frameBuffer;
291 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
292 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
295 const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof( uint32_t );
296 uint8_t* frameBuffer;
298 WebPAnimDecoderGetNext( mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp );
300 pixelBuffer = Dali::Devel::PixelBuffer::New( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888 );
301 memcpy( pixelBuffer.GetBuffer(), frameBuffer, bufferSize );
302 mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
304 mImpl->mLoadingFrame++;
305 if( mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count )
307 mImpl->mLoadingFrame = 0;
308 WebPAnimDecoderReset( mImpl->mWebPAnimDecoder );
314 ImageDimensions WebPLoading::GetImageSize() const
316 #ifdef DALI_WEBP_ENABLED
317 return ImageDimensions( mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height );
319 return ImageDimensions();
323 uint32_t WebPLoading::GetImageCount() const
325 #ifdef DALI_WEBP_ENABLED
326 return mImpl->mWebPAnimInfo.frame_count;
332 uint32_t WebPLoading::GetFrameInterval( uint32_t frameIndex ) const
334 if( frameIndex >= GetImageCount() )
342 return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
344 return mImpl->mTimeStamp[frameIndex];
348 std::string WebPLoading::GetUrl() const
353 } // namespace Adaptor
355 } // namespace Internal